diff --git a/cogs/gameplay.py b/cogs/gameplay.py index 354efc0..ecda284 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -11,7 +11,7 @@ import pygsheets from sqlmodel import or_ from api_calls import db_get -from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, get_full_roster_from_sheets, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, manual_end_game, popouts, read_lineup, show_defense_cards, singles, starting_pitcher_dropdown_view, strikeouts, triples, undo_play, update_game_settings, walks +from command_logic.logic_gameplay import advance_runners, bunts, chaos, complete_game, doubles, flyballs, get_full_roster_from_sheets, get_lineups_from_sheets, checks_log_interaction, complete_play, get_scorebug_embed, hit_by_pitch, homeruns, is_game_over, manual_end_game, popouts, read_lineup, show_defense_cards, singles, starting_pitcher_dropdown_view, steals, strikeouts, triples, undo_play, update_game_settings, walks, xchecks from dice import ab_roll from exceptions import GameNotFoundException, GoogleSheetsException, TeamNotFoundException, PlayNotFoundException, GameException, log_exception from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, get_channel, team_role, user_has_role, random_gif, random_from_list @@ -20,7 +20,7 @@ from helpers import DEFENSE_LITERAL, PD_PLAYERS_ROLE_NAME, get_channel, team_rol from in_game.ai_manager import get_starting_pitcher, get_starting_lineup from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check from in_game.gameplay_models import Lineup, Play, Session, engine, player_description, select, Game -from in_game.gameplay_queries import get_and_cache_position, get_available_pitchers, get_channel_game_or_none, get_active_games_by_team, get_game_lineups, get_team_or_none, get_card_or_none +from in_game.gameplay_queries import get_position, get_available_pitchers, get_channel_game_or_none, get_active_games_by_team, get_game_lineups, get_team_or_none, get_card_or_none from utilities.buttons import Confirm, ScorebugButtons, ask_confirm from utilities.dropdown import DropdownView, SelectStartingPitcher @@ -274,7 +274,7 @@ class Gameplay(commands.Cog): await final_message.edit(content=f'The {ai_team.sname} lineup is in, pulling in scouting data...') for batter in batter_lineups: if batter.position != 'DH': - await get_and_cache_position(session, batter.card, batter.position) + await get_position(session, batter.card, batter.position) # session.refresh(this_game) @@ -564,6 +564,58 @@ class Gameplay(commands.Cog): await self.complete_and_post_play(session, interaction, this_play) + @group_log.command(name='stealing', description='Running: stolen-base, caught-stealing') + @app_commands.describe(to_base='Base the runner is advancing to; 2 for 2nd, 3 for 3rd, 4 for Home') + async def log_stealing(self, interaction: discord.Interaction, running_type: Literal['stolen-base', 'caught-stealing', 'steal-plus-overthrow'], to_base: Literal[2, 3, 4]): + with Session(engine) as session: + this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log stealing') + + if (to_base == 2 and this_play.on_first is None) or (to_base == 3 and this_play.on_second is None) or (to_base == 4 and this_play.on_third is None): + logger.info(f'Illegal steal attempt') + await interaction.edit_original_response( + content=f'I don\'t see a runner there.' + ) + return + + if (to_base == 3 and this_play.on_third is not None) or (to_base == 2 and this_play.on_second is not None): + logger.info(f'Stealing runner is blocked') + if to_base == 3: + content = f'{this_play.on_second.player.name} is blocked by {this_play.on_third.player.name}' + else: + content = f'{this_play.on_first.player.name} is blocked by {this_play.on_second.player.name}' + + await interaction.edit_original_response( + content=content + ) + return + + logger.info(f'log stealing - this_play: {this_play}') + this_play = await steals(session, interaction, this_play, running_type, to_base) + + await self.complete_and_post_play(session, interaction, this_play) + + @group_log.command(name='xcheck', description='Defender makes an x-check') + @app_commands.choices(position=[ + Choice(name='Pitcher', value='P'), + Choice(name='Catcher', value='C'), + Choice(name='First Base', value='1B'), + Choice(name='Second Base', value='2B'), + Choice(name='Third Base', value='3B'), + Choice(name='Shortstop', value='SS'), + Choice(name='Left Field', value='LF'), + Choice(name='Center Field', value='CF'), + Choice(name='Right Field', value='RF'), + ]) + async def log_xcheck_command(self, interaction: discord.Interaction, position: Choice[str]): + with Session(engine) as session: + this_game, owner_team, this_play = await checks_log_interaction(session, interaction, command_name='log xcheck') + + logger.info(f'log xcheck - this_play: {this_play}') + this_play = await xchecks(session, interaction, this_play, position.value) + + await self.complete_and_post_play(session, interaction, this_play) + + @group_log.command(name='undo-play', description='Roll back most recent play from the log') async def log_undo_play_command(self, interaction: discord.Interaction): with Session(engine) as session: diff --git a/cogs/gameplay_legacy.py b/cogs/gameplay_legacy.py index 4c52e59..90c043f 100644 --- a/cogs/gameplay_legacy.py +++ b/cogs/gameplay_legacy.py @@ -14,7 +14,7 @@ from discord.ext import commands, tasks from peewee import IntegrityError from typing import Literal, Optional -from dice import sa_fielding_roll +from dice import sa_fielding_roll_legacy from helpers import SBA_PLAYERS_ROLE_NAME, PD_PLAYERS_ROLE_NAME, random_conf_gif, SBA_SEASON, PD_SEASON, IMAGES, \ get_pos_abbrev, SBA_COLOR, get_roster_lineups, give_packs, send_to_channel, \ get_channel, team_role, get_cal_user, ButtonOptions, get_ratings_guide, \ @@ -4142,7 +4142,7 @@ class Gameplay(commands.Cog): defender_embed.set_image(url=defender['image']) embeds = [defender_embed] - dice_embeds = sa_fielding_roll(position.value, def_team) + dice_embeds = sa_fielding_roll_legacy(position.value, def_team) embeds.extend(dice_embeds) all_embeds = [x for x in embeds if x is not None] diff --git a/command_logic/logic_gameplay.py b/command_logic/logic_gameplay.py index 94af853..52fdb21 100644 --- a/command_logic/logic_gameplay.py +++ b/command_logic/logic_gameplay.py @@ -10,11 +10,12 @@ from sqlalchemy import delete from typing import Literal from api_calls import db_delete, db_get, db_post +from dice import sa_fielding_roll from exceptions import * from helpers import DEFENSE_LITERAL, SBA_COLOR, get_channel from in_game.game_helpers import legal_check from in_game.gameplay_models import BattingCard, Game, Lineup, PositionRating, RosterLink, Team, Play -from in_game.gameplay_queries import get_and_cache_position, get_available_pitchers, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_game_lineups, get_last_team_play, get_one_lineup, get_player_id_from_dict, get_player_name_from_dict, get_player_or_none, get_sorted_lineups, get_team_or_none, get_players_last_pa, post_game_rewards +from in_game.gameplay_queries import get_position, get_available_pitchers, get_card_or_none, get_channel_game_or_none, get_db_ready_decisions, get_db_ready_plays, get_game_lineups, get_last_team_play, get_one_lineup, get_player_id_from_dict, get_player_name_from_dict, get_player_or_none, get_sorted_lineups, get_team_or_none, get_players_last_pa, post_game_rewards from utilities.buttons import ButtonOptions, Confirm, ask_confirm from utilities.dropdown import DropdownView, SelectStartingPitcher, SelectViewDefense from utilities.embeds import image_embed @@ -170,7 +171,7 @@ async def get_scorebug_embed(session: Session, this_game: Game, full_length: boo bat_string = f'{curr_play.batter.batting_order}. {battingcard.hand.upper()} | {curr_play.batter.player.name_card_link('batting')}' if len(baserunner_string) > 0: pitchingcard = curr_play.pitcher.card.pitcherscouting.pitchingcard - pit_string += f'\nHold: {pitchingcard.hold}, WP: {pitchingcard.wild_pitch}, Bk: {pitchingcard.balk}' + pit_string += f'\nHold: {"+" if pitchingcard.hold > 0 else ""}{pitchingcard.hold}, WP: {pitchingcard.wild_pitch}, Bk: {pitchingcard.balk}' # battingcard = curr_play.batter.card.batterscouting.battingcard # bat_string += f'\nBunt: {battingcard.bunting}, HnR: {battingcard.hit_and_run}' @@ -280,7 +281,7 @@ async def read_lineup(session: Session, interaction: discord.Interaction, this_g for batter in human_lineups: if batter.position != 'DH': - await get_and_cache_position(session, batter.card, batter.position) + await get_position(session, batter.card, batter.position) return this_game.initialize_play(session) @@ -1460,7 +1461,7 @@ async def bunts(session: Session, interaction: discord.Interaction, this_play: P await question.edit(content='You keep thinking on it and try again.', view=None) log_exception(NoPlayerResponseException, f'{interaction.user.name} did not know who was fielding the bunt.') - def_pos = await get_and_cache_position(session, defender.card, defender.position) + def_pos = await get_position(session, defender.card, defender.position) lead_runner_out = await ask_confirm( interaction=interaction, @@ -1534,6 +1535,142 @@ async def chaos(session: Session, interaction: discord.Interaction, this_play: P session.refresh(this_play) return this_play +async def steals(session: Session, interaction: discord.Interaction, this_play: Play, steal_type: Literal['stolen-base', 'caught-stealing', 'steal-plus-overthrow'], to_base: Literal[2, 3, 4]) -> Play: + advance_runners(session, this_play, 0) + + if steal_type in ['stolen-base', 'steal-plus-overthrow']: + this_play.sb = 1 + this_play.error = 1 if steal_type == 'steal-plus-overthrow' else 0 + + if to_base == 4 and this_play.on_third: + this_play.runner = this_play.on_third + this_play.on_third_final = 4 + log_run_scored(session, this_play.on_third, this_play) + + if this_play.on_second: + this_play.on_second_final = 3 + if steal_type == 'steal-plus-overthrow': + this_play.on_second_final = 4 + log_run_scored(session, this_play.on_second, this_play, is_earned=False) + if this_play.on_first: + this_play.on_first_final = 2 if steal_type == 'stolen-base' else 3 + + elif to_base == 3 and this_play.on_second: + this_play.runner = this_play.on_second + this_play.on_second_final = 3 + + if this_play.on_first: + this_play.on_first_final = 2 + + if steal_type == 'steal-plus-overthrow': + this_play.on_second_final = 4 + log_run_scored(session, this_play.on_second, this_play, is_earned=False) + if this_play.on_first: + this_play.on_first_final = 3 + + else: + this_play.runner = this_play.on_first + this_play.on_first_final = 2 if steal_type == 'stolen-base' else 3 + + elif steal_type == 'caught-stealing': + this_play.outs = 1 + + if to_base == 4 and this_play.on_third: + this_play.runner = this_play.on_third + this_play.on_third_final = None + + if this_play.on_second: + this_play.on_second_final = 3 + if this_play.on_first: + this_play.on_first_final = 2 + + elif to_base == 3 and this_play.on_second: + this_play.runner = this_play.on_second + this_play.on_second_final = None + + if this_play.on_first: + this_play.on_first_final = 2 + + else: + this_play.runner = this_play.on_first + this_play.on_first_final = None + + + session.add(this_play) + session.commit() + + session.refresh(this_play) + return this_play + +async def xchecks(session: Session, interaction: discord.Interaction, this_play: Play, position: str) -> Play: + defense_team = this_play.pitcher.team + this_defender = get_one_lineup( + session, + this_play.game, + this_team=defense_team, + position=position + ) + + defender_embed = defense_team.embed + defender_embed.title = f'{defense_team.sname} {position} Check' + defender_embed.description = f'{this_defender.player.name}' + defender_embed.set_image(url=this_defender.player.image) + embeds = [defender_embed] + + this_rating = await get_position(session, this_defender.card, position) + this_roll = sa_fielding_roll(defense_team, this_play, position, this_rating) + + question = f'Looks like this is a {this_roll.hit_result}' + if this_roll.is_chaos: + question += ' **rare play**.' + elif this_roll.error_result is not None: + question += f' plus {this_roll.error_result}-base error.' + question += f'Is that correct?' + + await interaction.edit_original_response( + content=None, + embeds=this_roll.embeds + ) + is_correct = await ask_confirm( + interaction, + question, + label_type='yes', + timeout=30, + ) + + hit_result = this_roll.hit_result + error_result = this_roll.error_result + is_rare_play = this_roll.is_chaos + + if not is_correct: + # Full questionnaire + pass + + if hit_result == 'SPD': + is_out = ask_confirm( + interaction, + f'Is {this_play.batter.player.name} thrown out at first?', + custom_confirm_label='Out at first', + custom_cancel_label='Safe at first' + ) + if is_out: + hit_result = 'G3' + else: + this_play = await singles(session, interaction, this_play, '*') + + if hit_result not in ['SI1', 'SI2', 'DO2', 'DO3', 'TR'] and error_result is None: + + if this_play.on_base_code == 0: + this_play.ab, this_play.outs = 1, 1 + + # TODO: Continue working through results + # elif this_play + + session.add(this_play) + session.commit() + + session.refresh(this_play) + return this_play def activate_last_play(session: Session, this_game: Game) -> Play: p_query = session.exec(select(Play).where(Play.game == this_game).order_by(Play.id.desc()).limit(1)).all() @@ -2060,4 +2197,246 @@ async def manual_end_game(session: Session, interaction: discord.Interaction, th await complete_game(session, interaction, current_play) +async def gb_result(session: Session, interaction: discord.Interaction, this_play: Play, groundball_result: int, to_mif: bool = None, to_right_side: bool = None): + """ + Commits this_play + """ + if groundball_result == 1: + this_play = gb_result_1(session, this_play) + elif groundball_result == 2: + this_play = gb_result_2(session, this_play) + elif groundball_result == 3: + this_play = gb_result_3(session, this_play) + elif groundball_result == 4: + this_play = gb_result_4(session, this_play) + elif groundball_result == 5: + this_play = gb_result_5(session, this_play, to_mif) + elif groundball_result == 6: + this_play = gb_result_6(session, this_play, to_right_side) + elif groundball_result == 7: + this_play = gb_result_7(session, this_play) + elif groundball_result == 8: + this_play = gb_result_8(session, this_play) + elif groundball_result == 9: + this_play = gb_result_9(session, this_play) + elif groundball_result == 10: + this_play = gb_result_10(session, this_play) + elif groundball_result == 11: + this_play = gb_result_11(session, this_play) + elif groundball_result == 12: + this_play = gb_result_12(session, this_play, interaction) + elif groundball_result == 13: + this_play = gb_result_13(session, this_play) + session.add(this_play) + session.commit() + session.refresh(this_play) + + return this_play + + +def gb_result_1(session: Session, this_play: Play): + logger.info(f'GB 1') + this_play = advance_runners(session, this_play, 0) + this_play.ab, this_play.ab, this_play.outs = 1, 1, 1 + + return this_play + + +def gb_result_2(session: Session, this_play: Play): + logger.info(f'GB 2') + num_outs = 2 if this_play.starting_outs <= 1 else 1 + + this_play.ab, this_play.outs = 1, 1 + this_play.on_first_final = None + + if num_outs + this_play.starting_outs < 3: + if this_play.on_second: + this_play.on_second_final = 3 + if this_play.on_third: + this_play.on_third_final = 4 + log_run_scored(session, runner=this_play.on_third, this_play=this_play) + + return this_play + + +def gb_result_3(session: Session, this_play: Play): + logger.info(f'GB 3') + if this_play.starting_outs < 2: + this_play = advance_runners(session, this_play, 1) + + this_play.ab, this_play.outs = 1, 1 + return this_play + + +def gb_result_4(session: Session, this_play: Play): + logger.info(f'GB 4') + if this_play.starting_outs < 2: + this_play = advance_runners(session, this_play, 1) + + this_play.ab, this_play.outs = 1, 1 + this_play.on_first_final = None + + return this_play + + +def gb_result_5(session: Session, this_play: Play, to_mif: bool): + logger.info(f'GB 5') + this_play.ab, this_play.outs = 1, 1 + + if to_mif: + this_play = gb_result_3(session, this_play) + else: + this_play = gb_result_1(session, this_play) + + return this_play + + +def gb_result_6(session: Session, this_play: Play, to_right_side: bool): + logger.info(f'GB 6') + this_play.ab, this_play.outs = 1, 1 + + if to_right_side: + this_play = gb_result_3(session, this_play) + else: + this_play = gb_result_1(session, this_play) + + return this_play + + +def gb_result_7(session: Session, this_play: Play): + logger.info(f'GB 7') + this_play.ab, this_play.outs = 1, 1 + this_play = advance_runners(session, this_play, num_bases=1, only_forced=True) + return this_play + + +def gb_result_8(session: Session, this_play: Play): + logger.info(f'GB 8') + return gb_result_7(session, this_play) + + +def gb_result_9(session: Session, this_play: Play): + logger.info(f'GB 9') + this_play.ab, this_play.outs = 1, 1 + this_play.on_third_final = 3 + this_play.on_first_final = 2 + return this_play + + +def gb_result_10(session: Session, this_play: Play): + logger.info(f'GB 10') + num_outs = 2 if this_play.starting_outs <= 1 else 1 + this_play.ab, this_play.outs = 1, num_outs + this_play.on_second_final = 3 + this_play.on_first_final = 2 + return this_play + + +def gb_result_11(session: Session, this_play: Play): + logger.info(f'GB 11') + this_play.ab, this_play.outs = 1, 1 + this_play.on_first_final = 2 + this_play.on_second_final = 3 + this_play.batter_final = 1 + return this_play + + +async def gb_decide(session: Session, this_play: Play, interaction: discord.Interaction): + logger.info(f'GB Decide') + runner = this_play.on_third if this_play.on_third is not None else this_play.on_second + pos_rating = await get_position(session, this_play.defender.card, this_play.check_pos) + safe_range = runner.card.batterscouting.battingcard.running - 4 + pos_rating.range + + if this_play.game.ai_team is not None and this_play.ai_is_batting: + run_resp = this_play.managerai.gb_decide_run(session, this_play.game) + + if this_play.on_second is None: + log_exception(InvalidResultException, 'Cannot run GB Decide without a runner on second.') + + if safe_range >= run_resp.min_safe: + is_lead_running = True + else: + is_lead_running = False + + else: + is_lead_running = await ask_confirm( + interaction, + f'Is {runner.card.player.name} attempting to advance to third?', + label_type='yes', + delete_question=False + ) + + if not is_lead_running: + this_play = advance_runners(session, this_play, 0) + this_play.outs = 1 + + else: + if this_play.game.ai_team is not None and not this_play.ai_is_batting: + throw_resp = this_play.managerai.gb_decide_throw( + session, + this_play.game, + runner_speed=runner.card.batterscouting.battingcard.running, + defender_range=pos_rating.range + ) + throw_for_lead = throw_resp.at_lead_runner + await interaction.channel.send( + content=f'**{this_play.defender.player.name}** is {"not" if not throw_for_lead else ""} throwing for {runner.player.name}{"!" if throw_for_lead else "."}' + ) + else: + throw_for_lead = await ask_confirm( + interaction, + f'Is {this_play.defender.player.name} throwing for {runner.player.name}?', + label_type='yes' + ) + + if not throw_for_lead: + if this_play.starting_outs < 2: + this_play = advance_runners(session, this_play, 1) + this_play.outs = 1 + + else: + is_lead_out = await ask_confirm( + interaction, + f'Was {runner.card.player.name} thrown out?', + custom_confirm_label='Thrown Out', + custom_cancel_label='Safe' + ) + + if is_lead_out: + this_play.outs = 1 + this_play.batter_final = 1 + + if this_play.on_third: + this_play.on_first_final = 2 if this_play.on_first is not None else 0 + this_play.on_second_final = 3 if this_play.on_second is not None else 0 + elif this_play.on_second: + this_play.on_first_final = 2 if this_play.on_first is not None else 0 + + else: + this_play = advance_runners(session, this_play, num_bases=1) + this_play.batter_final = 1 + + return this_play + + +async def gb_result_12(session: Session, this_play: Play, interaction: discord.Interaction): + logger.info(f'GB 12') + if this_play.check_pos in ['1B', '2B']: + return gb_result_3(session, this_play) + elif this_play.check_pos == '3B': + return gb_result_1(session, this_play) + else: + return await gb_decide(session, this_play, interaction) + + +def gb_result_13(session: Session, this_play: Play): + logger.info(f'GB 13') + if this_play.check_pos in ['C', '3B']: + num_outs = 2 if this_play.starting_outs <= 1 else 1 + this_play.ab, this_play.outs = 1, num_outs + this_play.batter_final = 1 + else: + this_play = gb_result_2(session, this_play) + + return this_play diff --git a/dice.py b/dice.py index c8266cf..9197f9a 100644 --- a/dice.py +++ b/dice.py @@ -1,11 +1,12 @@ import logging +from typing import Literal import discord import random import pydantic from helpers import INFIELD_X_CHART, OUTFIELD_X_CHART -from in_game.gameplay_models import Game, Team +from in_game.gameplay_models import Game, Play, PositionRating, Team logger = logging.getLogger('discord_app') @@ -29,6 +30,12 @@ class JumpRoll(DiceRoll): pass +class FieldingRoll(DiceRoll): + d_six_three: int | None = None + hit_result: Literal['SI1', 'SI2', 'DO2', 'DO3', 'TR', 'G1', 'G2', 'G3', 'G1#', 'G2#', 'G3#', 'F1', 'F2', 'F3', 'SPD'] | None = None + error_result: Literal[1, 2, 3] | None = None + + def get_dice_embed(team: Team = None, embed_title: str = None): if team: embed = discord.Embed( @@ -45,7 +52,7 @@ def get_dice_embed(team: Team = None, embed_title: str = None): return embed -def sa_fielding_roll(pos_code: str, team: dict) -> list[discord.Embed]: +def sa_fielding_roll_legacy(pos_code: str, team: dict) -> list[discord.Embed]: """ Make a Super Advanced fielding check. """ @@ -794,6 +801,1939 @@ def sa_fielding_roll(pos_code: str, team: dict) -> list[discord.Embed]: return [roll_embed, chart_embed, error1_embed, error2_embed] +def sa_fielding_roll(this_team: Team, this_play: Play, pos_code: str, def_rating: PositionRating) -> FieldingRoll: + x_chart = None + error_chart = 'https://sombaseball.ddns.net/static/images/season04/error-' + range_note = None + error_note = None + error_note1 = None + error_note2 = None + symbol_link = 'https://docs.google.com/document/d/1wu63XSgfQE2wadiegWaaDda11QvqkN0liRurKm0vcTs/edit#heading=h.7oj0v3t1kc6o' + + this_roll = FieldingRoll( + d_six_one = random.randint(1, 6), + d_six_two = random.randint(1, 6), + d_six_three = random.randint(1, 6), + d_twenty = random.randint(1, 20) + ) + error_dice = this_roll.d_six_one + this_roll.d_six_two + this_roll.d_six_three + + if pos_code in ['1B', '2B', '3B', 'SS']: + x_chart = 'https://sombaseball.ddns.net/static/images/season04/range-infield.png' + symbol_link = 'https://docs.google.com/document/d/1p8Y2On0301C1yq4ktyPxE4lXxrIALYaF1vbW6RkRpII/edit' \ + '#heading=h.qgqyxe5xb77m' + + # Build range note + if this_roll.d_twenty == 1: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G3# SI1 ----SI2----\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G3#' + elif def_rating.range == 2: + this_roll.hit_result = 'SI1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI2' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty == 2: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2# SI1 ----SI2----\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2#' + elif def_rating.range == 2: + this_roll.hit_result = 'SI1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI2' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty <= 4: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2# G3# SI1 --SI2--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2#' + elif def_rating.range == 2: + this_roll.hit_result = 'G3#' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty == 5: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 --G3#-- SI1 SI2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G3#' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty == 6: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2# G3# SI1 SI2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2#' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty <= 8: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2 --G3#-- SI1\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 9: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2 G3 --G3#--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty == 10: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 --G3#--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty <= 12: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 G3 G3#\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty == 13: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 --G3---\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 14: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- --G2--- G3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty <= 16: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----G1----- G2 G3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 17: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------G1------- G3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty <= 19: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------G1------- G2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G2' + + elif this_roll.d_twenty == 20: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--------G1---------\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G1' + + + if pos_code == '1B': + error_chart += 'first-base.png' + + if error_dice == 18: + error_note = '2-base error for e3 -> e12, e19 -> e28\n' \ + '1-base error for e1, e2, e30' + if def_rating.error in [*range(3, 13), *range(19, 29)]: + this_roll.error_result = 2 + elif def_rating.error in [1, 2, 30]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '2-base error for e13 -> e28\n' \ + '1-base error for e1, e5, e8, e9, e29' + if def_rating.error in [*range(13, 29)]: + this_roll.error_result = 2 + elif def_rating.error in [1, 5, 8, 9, 29]: + this_roll.error_result = 1 + + elif error_dice == 16: + error_note = '2-base error for e29, e30\n' \ + '1-base error for e2, e8, e16, e19, e23' + if def_rating.error in [29, 30]: + this_roll.error_result = 2 + elif def_rating.error in [2, 8, 16, 19, 23]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '1-base error for e3, e8, e10 -> e12, e19, e20, e26, e30' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [3, 8, 10, 11, 12, 19, 20, 26, 30]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '1-base error for e4, e5, e9, e15, e18, e22, e24 -> e28' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [4, 5, 9, 15, 18, 22, 24]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '1-base error for e6, e13, e24, e26 -> e28, e30' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [6, 13, 24, 26, 27, 28, 30]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '1-base error for e14 -> e18, e21 -> e26, e28 -> e30' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [*range(14, 18), *range(21, 27), 28, 29, 30]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '1-base error for e10, e13, e16 -> e20, e23 -> e25, e27 -> e30' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [10, 13, *range(16, 21), 23, 24, 25, *range(27, 31)]: + this_roll.error_result = 1 + + elif error_dice == 10: + error_note = '1-base error for e19 -> e21, e23, e29' + error_note = '1-base error for e10, e13, e16 -> e20, e23 -> e25, e27 -> e30' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [10, 13, *range(16, 21), 23, 24, 25, *range(27, 31)]: + this_roll.error_result = 1 + + elif error_dice == 9: + error_note = '1-base error for e7, e12, e14, e21, e25, e26, e29' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [7, 12, 14, 21, 25, 26, 29]: + this_roll.error_result = 1 + + elif error_dice == 8: + error_note = '1-base error for e11, e27' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [11, 27]: + this_roll.error_result = 1 + + elif error_dice == 7: + error_note = '1-base error for e9, e15, e22, e27, e28' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [9, 15, 22, 27, 28]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e8, e11, e12, e17, e20' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [8, 11, 12, 17, 20]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' \ + f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = 'No error' + elif error_dice == 3: + error_note = '2-base error for e8 -> e12, e24 -> e28\n' \ + '1-base error for e2, e3, e6, e7, e14, e16, e17, e21' + if def_rating.error in [*range(8, 13), *range(24, 29)]: + this_roll.error_result = 2 + elif def_rating.error in [2, 3, 6, 7, 14, 16, 17, 21]: + this_roll.error_result = 1 + + if pos_code == '2B': + error_chart += 'second-base.png' + + if error_dice == 18: + error_note = '2-base error for e4 -> e19, e28 -> e41, e53 -> e65\n' \ + '1-base error for e22, e24, e25, e27, e44, e50' + if def_rating.error in [*range(4, 20), *range(28, 42), *range(53, 66)]: + this_roll.error_result = 2 + elif def_rating.error in [22, 24, 25, 27, 44, 50]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '2-base error for e20 -> e41, e68, e71\n' \ + '1-base error for e3, e4, e8 -> e12, e15, e16, e19' + if def_rating.error in [*range(20, 42), 68, 71]: + this_roll.error_result = 2 + elif def_rating.error in [3, 4, *range(8, 13), 15, 16, 19]: + this_roll.error_result = 1 + + elif error_dice == 16: + error_note = '2-base error for e53 -> 71\n' \ + '1-base error for e5 -> 10, e14, e16, e29, e37' + if def_rating.error in [*range(53, 72)]: + this_roll.error_result = 2 + elif def_rating.error in [*range(5, 11), 14, 16, 29, 37]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '1-base error for e11, e12, e14, e16, e17, e19, e26 -> e28, e30, e32, e37, ' \ + 'e50 -> e62, e71' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [11, 12, 14, 16, 17, 19, 26, 27, 28, 30, 32, 37, *range(50, 63), 71]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '1-base error for e13, e15, e34, e47, e65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [13, 15, 34, 47, 65]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '1-base error for e18, e20, e21, e26 -> e28, e39, e41, e50, e56, e59, e65, e71' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [18, 20, 21, 26, 27, 28, 39, 41, 50, 56, 59, 65, 71]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '1-base error for e22, e30, e34, e39, e44, e47, e53, e56, e62, e68, e71' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [22, 30, 34, 39, 44, 47, 53, 56, 62, 68, 71]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '1-base error for e23 -> e25, e29, e32, e37, e41, e50, e53, e59, e62, e68' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [*range(23, 26), 29, 32, 37, 41, 50, 53, 59, 62, 68]: + this_roll.error_result = 1 + + elif error_dice == 10: + error_note = '1-base error for e68' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [68]: + this_roll.error_result = 1 + + elif error_dice == 9: + error_note = '1-base error for e44' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [44]: + this_roll.error_result = 1 + + elif error_dice == 8: + error_note = 'No error' + elif error_dice == 7: + error_note = '1-base error for e47, e65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [47, 65]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e17, e19, e56 -> 62' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [17, 19, *range(56, 63)]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' \ + f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '1-base error for e10, e21' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [10, 21]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '2-base error for e12 -> e19, e37 -> e41, e59 -> e65\n' \ + '1-base error for e2 -> e4, e6, e20, e25, e28, e29' + if def_rating.error in [*range(12, 20), *range(37, 42), *range(59, 66)]: + this_roll.error_result = 2 + elif def_rating.error in [*range(2, 5), 6, 20, 25, 28, 29]: + this_roll.error_result = 1 + + if pos_code == '3B': + error_chart += 'third-base.png' + + if error_dice == 18: + error_note = '2-base error for e1, e2, e8, e10, e13 -> e16, e21 -> e24, e27, e30 -> e33, e50, ' \ + 'e56, e62, e65\n' \ + '1-base error for e39' + if def_rating.error in [1, 2, 8, 10, *range(13, 17), *range(21, 25), 27, *range(30, 34), 50, 56, 62, 65]: + this_roll.error_result = 2 + elif def_rating.error in [39]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '2-base error for e3 -> e10, e17, e18, e25 -> e27, e34 -> e37, e44, e47\n' \ + '1-base error for e11, e19, e32, e56' + if def_rating.error in [*range(3, 11), 17, 18, *range(25, 28), *range(34, 38), 44, 47]: + this_roll.error_result = 2 + elif def_rating.error in [11, 19, 32, 56]: + this_roll.error_result = 1 + + elif error_dice == 16: + error_note = '2-base error for e11 -> e18, e32, e33, e37, e53, e62, e65\n' \ + '1-base error for e4, e8, e19, e21, e22, e27, e41' + if def_rating.error in [*range(11, 19), 32, 33, 37, 53, 62, 65]: + this_roll.error_result = 2 + elif def_rating.error in [4, 8, 19, 21, 22, 27, 41]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '2-base error for e19 -> 27, e32, e33, e37, e39, e44, e50, e59\n' \ + '1-base error for e5 -> e8, e11, e14, e15, e17, e18, e28 -> e31, e34' + if def_rating.error in [*range(19, 28), 32, 33, 37, 39, 44, 50, 59]: + this_roll.error_result = 2 + elif def_rating.error in [*range(5, 9), 11, 14, 15, 17, 18, *range(28, 32), 34]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '2-base error for e28 -> e31, e34, e35, e50\n' \ + '1-base error for e14, e16, e19, e20, e22, e32, e39, e44, e56, e62' + if def_rating.error in [*range(28, 32), 34, 35, 50]: + this_roll.error_result = 2 + elif def_rating.error in [14, 16, 19, 20, 22, 32, 39, 44, 56, 62]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '2-base error for e41, e47, e53, e59\n' \ + '1-base error for e10, e15, e23, e25, e28, e30, e32, e33, e35, e44, e65' + if def_rating.error in [41, 47, 53, 59]: + this_roll.error_result = 2 + elif def_rating.error in [10, 15, 23, 25, 28, 30, 32, 33, 35, 44, 65]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '2-base error for e62\n' \ + '1-base error for e12, e17, e22, e24, e27, e29, e34 -> e50, e56 -> e59, e65' + if def_rating.error in [62]: + this_roll.error_result = 2 + elif def_rating.error in [12, 17, 22, 24, 27, 29, *range(34, 51), *range(56, 60), 65]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '2-base error for e56, e65\n' \ + '1-base error for e13, e18, e20, e21, e23, e26, e28, e31 -> e33, e35, e37, ' \ + 'e41 -> e53, e59, e65' + if def_rating.error in [56, 65]: + this_roll.error_result = 2 + elif def_rating.error in [13, 18, 20, 21, 23, 26, 28, *range(31, 34), 35, 37, *range(41, 54), 59, 65]: + this_roll.error_result = 1 + + elif error_dice == 10: + error_note = '1-base error for e26, e31, e41, e53 -> 65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [26, 31, 41, *range(53, 66)]: + this_roll.error_result = 1 + + elif error_dice == 9: + error_note = '1-base error for e24, e27, e29, e34, e37, e39, e47 -> e65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [24, 27, 29, 34, 37, 39, *range(47, 66)]: + this_roll.error_result = 1 + + elif error_dice == 8: + error_note = '1-base error for e25, e30, e33, e47, e53, e56, e62, e65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [25, 30, 33, 47, 53, 56, 62, 65]: + this_roll.error_result = 1 + + elif error_dice == 7: + error_note = '1-base error for e16, e19, e39, e59 -> e65' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [16, 19, 39, *range(59, 66)]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e21, e25, e30, e34, e53' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [21, 25, 30, 34, 53]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' \ + f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '1-base error for e2, e3, e6, e14, e16, e44' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [2, 3, 6, 14, 16, 44]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '2-base error for e10, e15, e16, e23, e24, e56\n' \ + '1-base error for e1 -> e4, e8, e14' + if def_rating.error in [10, 15, 16, 23, 24, 56]: + this_roll.error_result = 2 + elif def_rating.error in [*range(1, 5), 8, 14]: + this_roll.error_result = 1 + + if pos_code == 'SS': + error_chart += 'shortstop.png' + + if error_dice == 18: + error_note = '2-base error for e4 -> e12, e22 -> e32, e40 -> e48, e64, e68\n' \ + '1-base error for e1, e18, e34, e52, e56' + if def_rating.error in [*range(4, 13), *range(22, 33), *range(40, 49), 64, 68]: + this_roll.error_result = 2 + elif def_rating.error in [1, 18, 34, 52, 56]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '2-base error for e14 -> 32, e52, e56, e72 -> e84\n' \ + '1-base error for e3 -> e5, e8 ,e10, e36' + if def_rating.error in [*range(14, 33), 52, 56, *range(72, 85)]: + this_roll.error_result = 2 + elif def_rating.error in [*range(3, 6), 8, 10, 36]: + this_roll.error_result = 1 + + elif error_dice == 16: + error_note = '2-base error for e33 -> 56, e72\n' \ + '1-base error for e6 -> e10, e17, e18, e20, e28, e31, e88' + if def_rating.error in [*range(33, 57), 72]: + this_roll.error_result = 2 + elif def_rating.error in [*range(6, 11), 17, 18, 20, 28, 31, 88]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '2-base error for e60 -> e68, e76 -> 84\n' \ + '1-base error for e12, e14, e17, e18, e20 -> e22, e24, e28, e31 -> 36, e40, ' \ + 'e48, e72' + if def_rating.error in [*range(60, 69), *range(76, 85)]: + this_roll.error_result = 2 + elif def_rating.error in [12, 14, 17, 18, *range(20, 23), 24, 28, *range(31, 37), 40, 48, 72]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '1-base error for e16, e19, e38, e42, e60, e68' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [16, 19, 38, 42, 60, 68]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '1-base error for e23, e25, e32 -> 38, e44, e52, e72 -> 84' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [23, 25, *range(32, 39), 44, 52, *range(72, 85)]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '1-base error for e26, e27, e30, e42, e48, e56, e64, e68, e76 -> e88' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [26, 27, 30, 42, 48, 56, 64, 68, *range(76, 89)]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '1-base error for e29, e40, e52 -> e60, e72, e80 -> e88' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [29, 40, *range(52, 61), 72, *range(80, 89)]: + this_roll.error_result = 1 + + elif error_dice == 10: + error_note = '1-base error for e84' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [84]: + this_roll.error_result = 1 + + elif error_dice == 9: + error_note = '1-base error for e64, e68, e76, e88' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [64, 68, 76, 88]: + this_roll.error_result = 1 + + elif error_dice == 8: + error_note = '1-base error for e44' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [44]: + this_roll.error_result = 1 + + elif error_dice == 7: + error_note = '1-base error for e60' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [60]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e21, e22, e24, e28, e31, e48, e64, e72' + if def_rating.error in [None]: + this_roll.error_result = 2 + elif def_rating.error in [21, 22, 24, 28, 31, 48, 64, 72]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' \ + f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '2-base error for e72\n' \ + '1-base error for e14, e19, e20, e24, e25, e30, e31, e80' + if def_rating.error in [72]: + this_roll.error_result = 2 + elif def_rating.error in [14, 19, 20, 24, 25, 30, 31, 80]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '2-base error for e10, e12, e28 -> e32, e48, e84\n' \ + '1-base error for e2, e5, e7, e23, e27' + if def_rating.error in [10, 12, *range(28, 33), 48, 84]: + this_roll.error_result = 2 + elif def_rating.error in [2, 5, 7, 23, 27]: + this_roll.error_result = 1 + + elif pos_code in ['LF', 'CF', 'RF']: + x_chart = 'https://sombaseball.ddns.net/static/images/season04/range-outfield.png' + symbol_link = 'https://docs.google.com/document/d/1p8Y2On0301C1yq4ktyPxE4lXxrIALYaF1vbW6RkRpII/edit' \ + '#heading=h.drrzdsvu0ij0' + + # Build range note + if this_roll.d_twenty == 1: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'F1 DO2 DO3 --TR3--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F1' + elif def_rating.range == 2: + this_roll.hit_result = 'DO2' + elif def_rating.range == 3: + this_roll.hit_result = 'DO3' + elif def_rating.range == 4: + this_roll.hit_result = 'TR' + else: + this_roll.hit_result = 'TR' + elif this_roll.d_twenty == 2: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'F2 SI2 DO2 DO3 TR3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'SI2' + elif def_rating.range == 3: + this_roll.hit_result = 'DO2' + elif def_rating.range == 4: + this_roll.hit_result = 'DO3' + else: + this_roll.hit_result = 'TR' + + elif this_roll.d_twenty == 3: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'F2 SI2 --DO2-- DO3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'SI2' + elif def_rating.range == 3: + this_roll.hit_result = 'DO2' + elif def_rating.range == 4: + this_roll.hit_result = 'DO2' + else: + this_roll.hit_result = 'DO3' + + elif this_roll.d_twenty == 4: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'F2 F1 SI2 DO2 DO3\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI2' + elif def_rating.range == 4: + this_roll.hit_result = 'DO2' + else: + this_roll.hit_result = 'DO3' + + elif this_roll.d_twenty <= 6: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--F2--- --SI2-- DO2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'SI2' + elif def_rating.range == 4: + this_roll.hit_result = 'DO2' + else: + this_roll.hit_result = 'DO2' + + elif this_roll.d_twenty == 7: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--F2--- F1 SI2 DO2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'F1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'DO2' + + elif this_roll.d_twenty == 8: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--F2--- F1 --SI2--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'F1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty <= 11: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----F2----- --SI2--\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'F2' + elif def_rating.range == 4: + this_roll.hit_result = 'SI2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty <= 13: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----F2----- F1 SI2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F2' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'F2' + elif def_rating.range == 4: + this_roll.hit_result = 'F1' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty <= 15: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'F3 ----F2----- SI2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F3' + elif def_rating.range == 2: + this_roll.hit_result = 'F2' + elif def_rating.range == 3: + this_roll.hit_result = 'F2' + elif def_rating.range == 4: + this_roll.hit_result = 'F2' + else: + this_roll.hit_result = 'SI2' + + elif this_roll.d_twenty == 16: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--F3--- --F2--- F1\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F3' + elif def_rating.range == 2: + this_roll.hit_result = 'F3' + elif def_rating.range == 3: + this_roll.hit_result = 'F2' + elif def_rating.range == 4: + this_roll.hit_result = 'F2' + else: + this_roll.hit_result = 'F1' + + elif this_roll.d_twenty <= 18: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----F3----- F2 F1\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F3' + elif def_rating.range == 2: + this_roll.hit_result = 'F3' + elif def_rating.range == 3: + this_roll.hit_result = 'F3' + elif def_rating.range == 4: + this_roll.hit_result = 'F2' + else: + this_roll.hit_result = 'F1' + + elif this_roll.d_twenty == 19: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------F3------- F2\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F3' + elif def_rating.range == 2: + this_roll.hit_result = 'F3' + elif def_rating.range == 3: + this_roll.hit_result = 'F3' + elif def_rating.range == 4: + this_roll.hit_result = 'F3' + else: + this_roll.hit_result = 'F2' + + elif this_roll.d_twenty == 20: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--------F3---------\n' \ + '```\n\n' + if def_rating.range == 1: + this_roll.hit_result = 'F3' + elif def_rating.range == 2: + this_roll.hit_result = 'F3' + elif def_rating.range == 3: + this_roll.hit_result = 'F3' + elif def_rating.range == 4: + this_roll.hit_result = 'F3' + else: + this_roll.hit_result = 'F3' + + if pos_code in ['LF', 'RF']: + error_chart += 'corner-outfield.png' + + if error_dice == 18: + error_note = '3-base error for e4 -> e12, e19 -> e25\n' \ + '2-base error for e18\n' \ + '1-base error for e2, e3, e15' + if def_rating.error in [*range(4, 13), *range(19, 26)]: + this_roll.error_result = 3 + elif def_rating.error in [18]: + this_roll.error_result = 2 + elif def_rating.error in [2, 3, 15]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '3-base error for e13 -> e25\n' \ + '2-base error for e1, e6, e8, e10' + if def_rating.error in [*range(13, 26)]: + this_roll.error_result = 3 + elif def_rating.error in [1, 6, 8, 10]: + this_roll.error_result = 2 + + elif error_dice == 16: + error_note = '2-base error for e2\n' \ + '1-base error for e7 -> 12, e22, e24, e25' + if def_rating.error in [2]: + this_roll.error_result = 2 + elif def_rating.error in [*range(7, 13), 22, 24, 25]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '2-base error for e3, e4, e7, e8, e10, e11, e13, e20, e21' + if def_rating.error in [3, 4, 7, 8, 10, 11, 13, 20, 21]: + this_roll.error_result = 2 + + elif error_dice == 14: + error_note = '2-base error for e5, e6, e10, e12, e14, e15, e22, e23' + if def_rating.error in [5, 6, 10, 12, 14, 15, 22, 23]: + this_roll.error_result = 2 + elif error_dice == 13: + error_note = '2-base error for e11, e12, e16, e20, e24, e25' + if def_rating.error in [11, 12, 16, 20, 24, 25]: + this_roll.error_result = 2 + + elif error_dice == 12: + error_note = '2-base error for e13 -> e18, e21 -> e23, e25' + if def_rating.error in [*range(13, 19), *range(21, 24), 25]: + this_roll.error_result = 2 + + elif error_dice == 11: + error_note = '2-base error for e9, e18 -> e21, e23 -> e25' + if def_rating.error in [9, *range(18, 22), *range(23, 26)]: + this_roll.error_result = 2 + + elif error_dice == 10: + error_note = '2-base error for e19' + if def_rating.error in [19]: + this_roll.error_result = 2 + + elif error_dice == 9: + error_note = '2-base error for e22' + if def_rating.error in [22]: + this_roll.error_result = 2 + + elif error_dice == 8: + error_note = '2-base error for e24' + if def_rating.error in [24]: + this_roll.error_result = 2 + + elif error_dice == 7: + error_note = '1-base error for e19 -> e21, e23' + if def_rating.error in [*range(19, 22), 23]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '2-base error for e7, e8\n' \ + '1-base error for e13 -> e18, e22, e24, e25' + if def_rating.error in [7, 8]: + this_roll.error_result = 2 + elif def_rating.error in [*range(13, 19), 22, 24, 25]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!' + error_note1 = f'**F1**: {OUTFIELD_X_CHART["f1"]["rp"]}\n' \ + f'**F2**: {OUTFIELD_X_CHART["f2"]["rp"]}\n' \ + f'**F3**: {OUTFIELD_X_CHART["f3"]["rp"]}\n' + error_note2 = f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' \ + f'**DO2**: {OUTFIELD_X_CHART["do2"]["rp"]}\n' \ + f'**DO3**: {OUTFIELD_X_CHART["do3"]["rp"]}\n' \ + f'**TR3**: {OUTFIELD_X_CHART["tr3"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '2-base error for e13, e16, e20, e23 -> e25\n' \ + '1-base error for e4 -> e6, e10 -> 12, e16 -> e18' + if def_rating.error in [13, 16, 20, *range(23, 26)]: + this_roll.error_result = 2 + elif def_rating.error in [*range(4, 7), *range(10, 13), *range(16, 19)]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '3-base error for e8 -> e12, e24, e25\n' \ + '2-base error for e19\n' \ + '1-base error for e1 -> e3, e6, e14, e15, e18, e20 -> e22' + if def_rating.error in [*range(8, 13), 24, 25]: + this_roll.error_result = 3 + elif def_rating.error == 19: + this_roll.error_result = 2 + elif def_rating.error in [*range(1, 4), 6, 14, 15, 18, *range(20, 23)]: + this_roll.error_result = 1 + + else: + error_chart += 'center-field.png' + + if error_dice == 18: + error_note = '3-base error for e4 -> 19\n' \ + '2-base error for e2, e25\n' \ + '1-base error for e3, e23' + if def_rating.error in [*range(4, 20)]: + this_roll.error_result = 3 + elif def_rating.error in [2, 25]: + this_roll.error_result = 2 + elif def_rating.error in [3, 23]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '3-base error for e20 -> e25\n' \ + '2-base error for e1, e2, e5, e7, e9, e13 -> e15, e17' + if def_rating.error in [*range(20, 26)]: + this_roll.error_result = 3 + elif def_rating.error in [1, 2, 5, 7, 9, *range(13, 16), 17]: + this_roll.error_result = 2 + + elif error_dice == 16: + error_note = '2-base error for e3 -> e5, e8, e23\n' \ + '1-base error for e10 -> e18' + if def_rating.error in [*range(3, 6), 8, 23]: + this_roll.error_result = 2 + elif def_rating.error in [*range(10, 19)]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '2-base error for e6 -> e8, e12, e13, e19' + if def_rating.error in [*range(6, 9), 12, 13, 19]: + this_roll.error_result = 2 + + elif error_dice == 14: + error_note = '2-base error for e9, e10, e16 -> e18, e20 -> e23' + if def_rating.error in [9, 10, *range(16, 19), *range(20, 24)]: + this_roll.error_result = 2 + + elif error_dice == 13: + error_note = '2-base error for e11, e18, e20, e23 -> e25' + if def_rating.error in [11, 18, 20, *range(23, 26)]: + this_roll.error_result = 2 + + elif error_dice == 12: + error_note = '2-base error for e14, e15, e21, e22, e24' + if def_rating.error in [14, 15, 21, 22, 24]: + this_roll.error_result = 2 + + elif error_dice == 11: + error_note = '2-base error for e19, e25' + if def_rating.error in [19, 25]: + this_roll.error_result = 2 + + elif error_dice >= 8: + error_note = 'No error' + elif error_dice == 7: + error_note = '2-base error for e16, e17' + if def_rating.error in [16, 17]: + this_roll.error_result = 2 + + elif error_dice == 6: + error_note = '2-base error for e12, e13\n' \ + '1-base error for e19 -> e25' + if def_rating.error in [12, 13]: + this_roll.error_result = 2 + elif def_rating.error in [*range(19, 26)]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!' + error_note1 = f'**F1**: {OUTFIELD_X_CHART["f1"]["rp"]}\n' \ + f'**F2**: {OUTFIELD_X_CHART["f2"]["rp"]}\n' \ + f'**F3**: {OUTFIELD_X_CHART["f3"]["rp"]}\n' + error_note2 = f'**SI2**: {OUTFIELD_X_CHART["si2"]["rp"]}\n' \ + f'**DO2**: {OUTFIELD_X_CHART["do2"]["rp"]}\n' \ + f'**DO3**: {OUTFIELD_X_CHART["do3"]["rp"]}\n' \ + f'**TR3**: {OUTFIELD_X_CHART["tr3"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '2-base error for e10, e12, e13, e20, e22, e23\n' \ + '1-base error for e3 -> e9, e15 -> e18' + if def_rating.error in [10, 12, 13, 20, 22, 23]: + this_roll.error_result = 2 + elif def_rating.error in [*range(3, 10), *range(15, 19)]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '3-base error for e12 -> e19\n' \ + '2-base error for e6, e10, e11\n' \ + '1-base error for e2, e3, e7 -> e9, e21 -> e23' + if def_rating.error in [*range(12, 20)]: + this_roll.error_result = 3 + elif def_rating.error in [6, 10, 11]: + this_roll.error_result = 2 + elif def_rating.error in [*range(2, 4), *range(7, 10), *range(21, 24)]: + this_roll.error_result = 1 + + elif pos_code == 'C': + x_chart = 'https://sombaseball.ddns.net/static/images/season07/range-catcher.png' + error_chart += 'catcher.png' + + # Build range note + if this_roll.d_twenty == 1: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G3 ------SI1------\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G3' + elif def_rating.range == 2: + this_roll.hit_result = 'SI1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 2: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G3 SPD ----SI1----\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G3' + elif def_rating.range == 2: + this_roll.hit_result = 'SPD' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 3: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G3--- SPD --SI1--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G3' + elif def_rating.range == 2: + this_roll.hit_result = 'G3' + elif def_rating.range == 3: + this_roll.hit_result = 'SPD' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 4: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2 G3 --SPD-- SI1\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2' + elif def_rating.range == 2: + this_roll.hit_result = 'G3' + elif def_rating.range == 3: + this_roll.hit_result = 'SPD' + elif def_rating.range == 4: + this_roll.hit_result = 'SPD' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 5: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2 --G3--- --SPD--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2' + elif def_rating.range == 2: + this_roll.hit_result = 'G3' + elif def_rating.range == 3: + this_roll.hit_result = 'G3' + elif def_rating.range == 4: + this_roll.hit_result = 'SPD' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 6: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G2--- G3 --SPD--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3' + elif def_rating.range == 4: + this_roll.hit_result = 'SPD' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 7: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'PO G2 G3 --SPD--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'PO' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3' + elif def_rating.range == 4: + this_roll.hit_result = 'SPD' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 8: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'PO --G2--- G3 SPD\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'PO' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 9: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--PO--- G2 G3 SPD\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'PO' + elif def_rating.range == 2: + this_roll.hit_result = 'PO' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 10: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'FO PO G2 G3 SPD\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'FO' + elif def_rating.range == 2: + this_roll.hit_result = 'PO' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'SPD' + + elif this_roll.d_twenty == 11: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'FO --PO--- G2 G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'FO' + elif def_rating.range == 2: + this_roll.hit_result = 'PO' + elif def_rating.range == 3: + this_roll.hit_result = 'PO' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 12: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--FO--- PO G2 G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'FO' + elif def_rating.range == 2: + this_roll.hit_result = 'FO' + elif def_rating.range == 3: + this_roll.hit_result = 'PO' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 13: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 FO PO G2 G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'FO' + elif def_rating.range == 3: + this_roll.hit_result = 'PO' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 14: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 --FO--- PO G2\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'FO' + elif def_rating.range == 3: + this_roll.hit_result = 'FO' + elif def_rating.range == 4: + this_roll.hit_result = 'PO' + else: + this_roll.hit_result = 'G2' + + elif this_roll.d_twenty <= 16: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- FO PO G2\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'FO' + elif def_rating.range == 3: + this_roll.hit_result = 'FO' + elif def_rating.range == 4: + this_roll.hit_result = 'PO' + else: + this_roll.hit_result = 'G2' + + elif this_roll.d_twenty <= 18: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----G1----- FO PO\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'FO' + else: + this_roll.hit_result = 'PO' + + elif this_roll.d_twenty == 19: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----G1----- --FO---\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'FO' + else: + this_roll.hit_result = 'FO' + + elif this_roll.d_twenty == 20: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------G1------- FO\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'FO' + + # Build error note + # error_dice = 5 + if error_dice == 18: + error_note = '2-base error for e4 -> 16\n1-base error for e2, e3' + if def_rating.error in [*range(4, 17)]: + this_roll.error_result = 2 + elif def_rating.error in [2, 3]: + this_roll.error_result = 1 + + elif error_dice == 17: + error_note = '1-base error for e1, e2, e4, e5, e12 -> e14, e16' + if def_rating.error in [1, 2, 4, 5, *range(12, 15), 16]: + this_roll.error_result = 1 + + elif error_dice == 16: + error_note = '1-base error for e3 -> e5, e7, e12 -> e14, e16' + if def_rating.error in [*range(3, 6), 7, *range(12, 15), 16]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '1-base error for e7, e8, e12, e13, e15' + if def_rating.error in [7, 8, 12, 13, 15]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '1-base error for e6' + if def_rating.error in [6]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '1-base error for e9' + if def_rating.error in [9]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '1-base error for e10, e14' + if def_rating.error in [10, 14]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '1-base error for e11, e15' + if def_rating.error in [11, 15]: + this_roll.error_result = 1 + + elif 8 <= error_dice <= 10: + error_note = 'No error' + + elif error_dice == 7: + error_note = '1-base error for e16' + if def_rating.error in [16]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e8, e12, e13' + if def_rating.error in [8, 12, 13]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play! Ignore range chart above and consult ranges below\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**PO**: {INFIELD_X_CHART["po"]["rp"]}\n' \ + f'**FO**: {INFIELD_X_CHART["fo"]["rp"]}\n' \ + f'**SPD**: {INFIELD_X_CHART["spd"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '1-base error for e5, e13' + if def_rating.error in [5, 13]: + this_roll.error_result = 1 + + else: + error_note = '2-base error for e12 -> e16\n1-base error for e2, e3, e7, e11' + if def_rating.error in [*range(12, 17)]: + this_roll.error_result = 2 + elif def_rating.error in [2, 3, 7, 11]: + this_roll.error_result = 1 + + elif pos_code == 'P': + x_chart = 'https://sombaseball.ddns.net/static/images/season04/range-pitcher.png' + error_chart += 'pitcher.png' + symbol_link = 'https://docs.google.com/document/d/1a_g6apg74ixcwJapNrbOJZAx7gVxGjeNm79c5XLjSF0/edit' \ + '#heading=h.fpjqmiv10r8l' + + # Build range note + if this_roll.d_twenty == 1: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G3# ------SI1------\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G3#' + elif def_rating.range == 2: + this_roll.hit_result = 'SI1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 2: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2# ------SI1------\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2#' + elif def_rating.range == 2: + this_roll.hit_result = 'SI1' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty <= 4: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2# G3# ----SI1----\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2#' + elif def_rating.range == 2: + this_roll.hit_result = 'G3#' + elif def_rating.range == 3: + this_roll.hit_result = 'SI1' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 5: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G2 --G3#-- --SI1--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G2' + elif def_rating.range == 2: + this_roll.hit_result = 'G3#' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 6: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2# G3# --SI1--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2#' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'SI1' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty <= 8: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2 --G3#-- SI1\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3#' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'SI1' + + elif this_roll.d_twenty == 9: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + 'G1 G2 G3 --G3#--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G2' + elif def_rating.range == 3: + this_roll.hit_result = 'G3' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty == 10: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 --G3#--\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3#' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty <= 12: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 G3 G3#\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'G3#' + + elif this_roll.d_twenty == 13: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- G2 --G3---\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G3' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 14: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--G1--- --G2--- G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G2' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty <= 16: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '----G1----- G2 G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G2' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty <= 18: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------G1------- G3\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G3' + + elif this_roll.d_twenty == 19: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '------G1------- G2\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G2' + + elif this_roll.d_twenty == 20: + range_note = '```\n' \ + ' 1 | 2 | 3 | 4 | 5\n' \ + '--------G1---------\n' \ + '```\n' + if def_rating.range == 1: + this_roll.hit_result = 'G1' + elif def_rating.range == 2: + this_roll.hit_result = 'G1' + elif def_rating.range == 3: + this_roll.hit_result = 'G1' + elif def_rating.range == 4: + this_roll.hit_result = 'G1' + else: + this_roll.hit_result = 'G1' + + # Build error note + if error_dice == 18: + error_note = '2-base error for e4 -> e12, e19 -> e28, e34 -> e43, e46 -> e48' + if def_rating.error in [*range(4, 13), *range(19, 29), *range(34, 44), *range(46, 49)]: + this_roll.error_result = 2 + + elif error_dice == 17: + error_note = '2-base error for e13 -> e28, e44 -> e50' + if def_rating.error in [*range(13, 29), *range(44, 51)]: + this_roll.error_result = 2 + + elif error_dice == 16: + error_note = '2-base error for e30 -> e48, e50, e51\n' \ + '1-base error for e8, e11, e16, e23' + if def_rating.error in [*range(30, 49), 50, 51]: + this_roll.error_result = 2 + elif def_rating.error in [8, 11, 16, 23]: + this_roll.error_result = 1 + + elif error_dice == 15: + error_note = '2-base error for e50, e51\n' \ + '1-base error for e10 -> e12, e19, e20, e24, e26, e30, e35, e38, e40, e46, e47' + if def_rating.error in [50, 51]: + this_roll.error_result = 2 + elif def_rating.error in [*range(10, 13), 19, 20, 24, 26, 30, 35, 38, 40, 46, 47]: + this_roll.error_result = 1 + + elif error_dice == 14: + error_note = '1-base error for e4, e14, e18, e21, e22, e26, e31, e35, e42, e43, e48 -> e51' + if def_rating.error in [4, 14, 18, 21, 22, 26, 31, 35, 42, 43]: + this_roll.error_result = 1 + elif def_rating.error in [*range(48, 52)]: + this_roll.error_result = 1 + + elif error_dice == 13: + error_note = '1-base error for e6, e13, e14, e21, e22, e26, e27, e30 -> 34, e38 -> e51' + if def_rating.error in [6, 13, 14, 21, 22, 26, 27, range(30, 35), range(38, 52)]: + this_roll.error_result = 1 + + elif error_dice == 12: + error_note = '1-base error for e7, e11, e12, e15 -> e19, e22 -> e51' + if def_rating.error in [6, 13, 14, 21, 22, 26, 27, range(30, 35), range(38, 52)]: + this_roll.error_result = 1 + + elif error_dice == 11: + error_note = '1-base error for e10, e13, e15, e17, e18, e20, e21, e23, e24, e27 -> 38, e40, e42, ' \ + 'e44 -> e51' + if def_rating.error in [10, 13, 15, 17, 18, 20, 21, 23, 24, range(27, 39), 40, 42, range(44, 52)]: + this_roll.error_result = 1 + + elif error_dice == 10: + error_note = '1-base error for e20, e23, e24, e27 -> e51' + if def_rating.error in [20, 23, 24, range(27, 52)]: + this_roll.error_result = 1 + + elif error_dice == 9: + error_note = '1-base error for e16, e19, e26, e28, e34 -> e36, e39 -> e51' + if def_rating.error in [16, 19, 26, 28, range(34, 37), range(39, 52)]: + this_roll.error_result = 1 + + elif error_dice == 8: + error_note = '1-base error for e22, e33, e38, e39, e43 -> e51' + if def_rating.error in [22, 33, 38, 39, range(43, 52)]: + this_roll.error_result = 1 + + elif error_dice == 7: + error_note = '1-base error for e14, e21, e36, e39, e42 -> e44, e47 -> e51' + if def_rating.error in [14, 21, 36, 39, range(42, 45), range(47, 52)]: + this_roll.error_result = 1 + + elif error_dice == 6: + error_note = '1-base error for e8, e22, e38, e39, e43 -> e51' + if def_rating.error in [8, 22, 38, 39, range(42, 52)]: + this_roll.error_result = 1 + + elif error_dice == 5: + error_note = f'Rare play!\n\n' \ + f'**G3**: {INFIELD_X_CHART["g3"]["rp"]}\n' \ + f'**G2**: {INFIELD_X_CHART["g2"]["rp"]}\n' \ + f'**G1**: {INFIELD_X_CHART["g1"]["rp"]}\n' \ + f'**SI1**: {INFIELD_X_CHART["si1"]["rp"]}\n' + this_roll.is_chaos = True + + elif error_dice == 4: + error_note = '1-base error for e15, e16, e40' + if def_rating.error in [15, 16, 40]: + this_roll.error_result = 1 + + elif error_dice == 3: + error_note = '2-base error for e8 -> e12, e26 -> e28, e39 -> e43\n' \ + '1-base error for e6, e7, e17, e30, e33, e44' + if def_rating.error in [range(8, 13), range(26, 29), range(39, 44)]: + this_roll.error_result = 2 + elif def_rating.error in [6, 7, 17, 30, 33, 44]: + this_roll.error_result = 1 + + roll_embed = get_dice_embed(this_team) + roll_embed.add_field(name=f'SA Fielding roll for {this_team.gmname}', value=this_roll.roll_message) + + chart_embed = get_dice_embed(this_team, f'{pos_code} Fielding Check Summary') + chart_embed.add_field(name='Range Result', value=range_note, inline=False) + chart_embed.add_field(name='Error Result', value=error_note, inline=False) + chart_embed.add_field( + name='Help Commands', + value=f'Run `!` for full chart readout (e.g. `!g1` or `!do3`)' + ) + reference_string = f'[Range Chart]({x_chart}) / [Error Chart]({error_chart}) / [Result Reference]({symbol_link})' + chart_embed.add_field(name='References', value=reference_string, inline=False) + + error1_embed, error2_embed = None, None + if error_note1: + error1_embed = get_dice_embed(this_team) + error1_embed.add_field(name='Error Results', value=error_note1) + if error_note2: + error2_embed = get_dice_embed(this_team) + error2_embed.add_field(name='Error Results', value=error_note2) + + this_roll.embeds = [roll_embed, chart_embed, error1_embed, error2_embed] + logger.info(f'Game {this_play.game.id} | Team {this_team.id} ({this_team.abbrev}): {this_roll.roll_message}') + return this_roll + + def frame_plate_check(team: dict, game_id: int): tens_digit = (game_id // 10) % 10 half_tens = round(tens_digit / 2) diff --git a/exceptions.py b/exceptions.py index 1b62ab8..caa38ad 100644 --- a/exceptions.py +++ b/exceptions.py @@ -73,3 +73,7 @@ class NoHumanTeamsException(GameException): class GoogleSheetsException(GameException): pass + + +class InvalidResultException(GameException): + pass diff --git a/in_game/gameplay_models.py b/in_game/gameplay_models.py index 1df3ac0..a64ab24 100644 --- a/in_game/gameplay_models.py +++ b/in_game/gameplay_models.py @@ -10,7 +10,7 @@ from sqlmodel import Session, SQLModel, UniqueConstraint, create_engine, select, from sqlalchemy import func, desc from exceptions import * -from in_game.managerai_responses import DefenseResponse, JumpResponse, TagResponse, ThrowResponse, UncappedRunResponse +from in_game.managerai_responses import DefenseResponse, JumpResponse, RunResponse, TagResponse, ThrowResponse, UncappedRunResponse logger = logging.getLogger('discord_app') @@ -545,7 +545,7 @@ class ManagerAi(ManagerAiBase, table=True): if this_play is None: raise GameException(f'No game found while checking tag_from_second') - ai_rd = this_play.ai_run_diff() + ai_rd = this_play.ai_run_diff aggression_mod = abs(self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5) adjusted_running = self.running + aggression_mod @@ -569,7 +569,7 @@ class ManagerAi(ManagerAiBase, table=True): if this_play is None: raise GameException(f'No game found while checking throw_at_uncapped') - ai_rd = this_play.ai_run_diff() + ai_rd = this_play.ai_run_diff aggression = self.ahead_aggression if ai_rd > 0 else self.behind_aggression current_outs = this_play.starting_outs + this_play.outs @@ -608,7 +608,7 @@ class ManagerAi(ManagerAiBase, table=True): if this_play is None: raise GameException(f'No game found while checking uncapped_advance_lead') - ai_rd = this_play.ai_run_diff() + ai_rd = this_play.ai_run_diff aggression = self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5 if ai_rd > 4: @@ -656,7 +656,7 @@ class ManagerAi(ManagerAiBase, table=True): if this_play is None: raise GameException(f'No game found while checking uncapped_advance_lead') - ai_rd = this_play.ai_run_diff() + ai_rd = this_play.ai_run_diff aggression = self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5 if self.starting_outs == 2 and self.on_base_code > 0: @@ -690,7 +690,33 @@ class ManagerAi(ManagerAiBase, table=True): if len(ai_note) == 0 and self.on_base_code > 0: ai_note += f'- play straight up\n' + + def gb_decide_run(self, session: Session, this_game: Game) -> RunResponse: + this_resp = RunResponse() + this_play = this_game.current_play_or_none(session) + if this_play is None: + raise GameException(f'No game found while checking gb_decide_run') + ai_rd = this_play.ai_run_diff + aggression = self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5 + + this_resp.min_safe = 15 - aggression # TODO: write this algorithm + return this_resp + + def gb_decide_throw(self, session: Session, this_game: Game, runner_speed: int, defender_range: int) -> ThrowResponse: + this_resp = ThrowResponse(at_lead_runner=True) + this_play = this_game.current_play_or_none(session) + if this_play is None: + raise GameException(f'No game found while checking gb_decide_throw') + + ai_rd = this_play.ai_run_diff + aggression = self.ahead_aggression - 5 if ai_rd > 0 else self.behind_aggression - 5 + + if (runner_speed - 4 + defender_range) <= (10 + aggression): + this_resp.at_lead_runner = True + + return this_resp + class CardsetBase(SQLModel): id: int | None = Field(default=None, primary_key=True) @@ -1093,7 +1119,8 @@ class PlayBase(SQLModel): def uppercase_strings(cls, value: str) -> str: return value.upper() - def ai_run_diff(self): + @property + def ai_run_diff(self) -> int: if self.game.ai_team == 'away': return self.away_score - self.home_score else: diff --git a/in_game/gameplay_queries.py b/in_game/gameplay_queries.py index e1ab093..1362d3c 100644 --- a/in_game/gameplay_queries.py +++ b/in_game/gameplay_queries.py @@ -33,6 +33,10 @@ class DecisionModel(pydantic.BaseModel): game_finished: int = 0 +def get_batting_team(session: Session, this_play: Play) -> Team: + return this_play.game.away_team if this_play.inning_half == 'top' else this_play.game.home_team + + def get_games_by_channel(session: Session, channel_id: int) -> list[Game]: logger.info(f'Getting games in channel {channel_id}') return session.exec(select(Game).where(Game.channel_id == channel_id, Game.active)).all() @@ -239,7 +243,7 @@ async def get_pitcher_scouting_or_none(session: Session, card: Card, skip_cache: ratings_vr=s_query['ratings'][0] if s_query['ratings'][0]['vs_hand'] == 'R' else s_query['ratings'][1], ratings_vl=s_query['ratings'][0] if s_query['ratings'][0]['vs_hand'] == 'L' else s_query['ratings'][1] ) - pos_rating = await get_and_cache_position(session, card, 'P') + pos_rating = await get_position(session, card, 'P') return scouting return None @@ -307,7 +311,7 @@ async def shared_get_scouting(session: Session, this_card: Card, which: Literal[ return this_scouting -async def get_and_cache_position(session: Session, this_card: Card, position: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF'], skip_cache: bool = False): +async def get_position(session: Session, this_card: Card, position: Literal['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF'], skip_cache: bool = False) -> PositionRating: logger.info(f'Pulling position rating for {this_card.player.name_with_desc} at {position}') if not skip_cache: this_pos = session.exec(select(PositionRating).where(PositionRating.player_id == this_card.player.id, PositionRating.position == position, PositionRating.variant == this_card.variant)).all() @@ -347,7 +351,6 @@ async def get_and_cache_position(session: Session, this_card: Card, position: Li log_exception(PositionNotFoundException, f'{position} ratings not found for {this_card.player.name_with_desc}') - async def get_or_create_ai_card(session: Session, player: Player, team: Team, skip_cache: bool = False, dev_mode: bool = False) -> Card: logger.info(f'Getting or creating card for {player.name_with_desc} on the {team.sname}') diff --git a/tests/command_logic/test_logic_gameplay.py b/tests/command_logic/test_logic_gameplay.py index 015664c..65f53f5 100644 --- a/tests/command_logic/test_logic_gameplay.py +++ b/tests/command_logic/test_logic_gameplay.py @@ -1,7 +1,7 @@ import pytest from sqlmodel import Session, select, func -from command_logic.logic_gameplay import advance_runners, doubles, get_obc, get_re24, get_wpa, complete_play, log_run_scored, strikeouts +from command_logic.logic_gameplay import advance_runners, doubles, get_obc, get_re24, get_wpa, complete_play, log_run_scored, strikeouts, steals from in_game.gameplay_models import Lineup, Play from tests.factory import session_fixture, Game @@ -194,3 +194,17 @@ async def test_doubles(session: Session): assert play_2_ghost_2.on_first_final == 3 +async def test_stealing(session: Session): + game_1 = session.get(Game, 1) + play_1 = session.get(Play, 1) + play_1.hit, play_1.batter_final = 1, 1 + play_2 = complete_play(session, play_1) + + assert play_2.play_num == 2 + + play_2 = await steals(session, None, play_2, 'stolen-base', to_base=2) + + assert play_2.on_first_final == 2 + assert play_2.sb == 1 + assert play_2.runner == play_2.on_first + diff --git a/utilities/dropdown.py b/utilities/dropdown.py index 0cb7cfa..dfea1a6 100644 --- a/utilities/dropdown.py +++ b/utilities/dropdown.py @@ -9,7 +9,7 @@ from sqlmodel import Session from exceptions import CardNotFoundException, log_exception from in_game.game_helpers import legal_check from in_game.gameplay_models import Game, Lineup, Play, Team -from in_game.gameplay_queries import get_and_cache_position, get_card_or_none +from in_game.gameplay_queries import get_position, get_card_or_none logger = logging.getLogger('discord_app') @@ -116,7 +116,7 @@ class SelectStartingPitcher(discord.ui.Select): ) return - await get_and_cache_position(self.session, human_sp_card, 'P') + await get_position(self.session, human_sp_card, 'P') legal_data = await legal_check([self.values[0]], difficulty_name=self.league_name) if not legal_data['legal']: