Complete /new-game campaign
Add scorebug function to Game Add card links prop to players Add scorebug prop to play
This commit is contained in:
parent
5fc89b5ce4
commit
19e781137e
@ -10,7 +10,7 @@ from api_calls import *
|
||||
from helpers import *
|
||||
import in_game
|
||||
from in_game import ai_manager
|
||||
from in_game.gameplay_models import Session, select, engine, Game, Cardset, Lineup, Team, Player
|
||||
from in_game.gameplay_models import Play, Session, select, engine, Game, Cardset, Lineup, Team, Player
|
||||
|
||||
|
||||
# date = f'{datetime.datetime.now().year}-{datetime.datetime.now().month}-{datetime.datetime.now().day}'
|
||||
@ -570,8 +570,9 @@ class Admins(commands.Cog):
|
||||
lineups = session.exec(select(Lineup.id)).all()
|
||||
teams = session.exec(select(Team.id)).all()
|
||||
players = session.exec(select(Player.id)).all()
|
||||
plays = session.exec(select(Play.id)).all()
|
||||
|
||||
output = f'## Database Counts\nGames: {len(games)}\nCardsets: {len(cardsets)}\nLineups: {len(lineups)}\nTeams: {len(teams)}\nPlayers: {len(players)}'
|
||||
output = f'## Database Counts\nGames: {len(games)}\nCardsets: {len(cardsets)}\nLineups: {len(lineups)}\nTeams: {len(teams)}\nPlayers: {len(players)}\nPlays: {len(plays)}'
|
||||
|
||||
await message.edit(content=output)
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ from discord.ext import commands, tasks
|
||||
import pygsheets
|
||||
|
||||
from api_calls import db_get
|
||||
from command_logic.gameplay import get_lineups_from_sheets
|
||||
from command_logic.logic_gameplay import get_lineups_from_sheets
|
||||
from helpers import PD_PLAYERS_ROLE_NAME, team_role, user_has_role, random_gif, random_from_list
|
||||
|
||||
# from in_game import ai_manager
|
||||
@ -218,7 +218,7 @@ class Gameplay(commands.Cog):
|
||||
await final_message.edit(
|
||||
content=f'{away_role.mention} @ {home_role.mention} is set!\n\n'
|
||||
f'Go ahead and set lineups with the `/read-lineup` command!',
|
||||
embed=this_game.get_scorebug(full_length=False)
|
||||
embed=this_game.get_scorebug_embed(session)
|
||||
)
|
||||
|
||||
@commands.command(name='force-endgame', help='Mod: Force a game to end without stats')
|
||||
@ -232,7 +232,7 @@ class Gameplay(commands.Cog):
|
||||
|
||||
await ctx.send(
|
||||
content=None,
|
||||
embed=this_game.get_scorebug(full_length=True)
|
||||
embed=this_game.get_scorebug_embed(session, include_lineups=True)
|
||||
)
|
||||
|
||||
view = Confirm(responders=[ctx.author], timeout=60, label_type='confirm')
|
||||
@ -316,7 +316,7 @@ class Gameplay(commands.Cog):
|
||||
|
||||
session.commit()
|
||||
|
||||
await interaction.edit_original_response(content=f'Lineups are read and logged!')
|
||||
await interaction.edit_original_response(content=None, embed=this_game.get_scorebug_embed(session))
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
|
||||
@ -13,7 +13,7 @@ from typing import Optional, Literal
|
||||
|
||||
from in_game import data_cache
|
||||
import in_game.gameplay_models as iggm
|
||||
from in_game.gameplay_models import Session, Game, Team
|
||||
from in_game.gameplay_models import Play, Session, Game, Team
|
||||
from in_game.gameplay_queries import get_or_create_ai_card, get_player_id_from_dict, get_player_or_none
|
||||
|
||||
db = SqliteDatabase(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import datetime
|
||||
import logging
|
||||
from typing import Literal
|
||||
import discord
|
||||
from sqlmodel import Session, SQLModel, create_engine, select, or_, Field, Relationship
|
||||
from sqlalchemy import func
|
||||
@ -105,15 +106,79 @@ class Game(SQLModel, table=True):
|
||||
back_cardsets += f'&backup_cardset_id={link.cardset_id}'
|
||||
return f'{pri_cardsets}{back_cardsets}'
|
||||
|
||||
def get_scorebug(self, full_length: bool = True) -> discord.Embed:
|
||||
return discord.Embed(
|
||||
title=f'{self.away_team_id} @ {self.home_team_id}',
|
||||
def current_play_or_none(self, session: Session):
|
||||
this_play = session.exec(select(Play).where(Play.game == self).order_by(Play.id.desc()).limit(1)).all()
|
||||
if len(this_play) == 1:
|
||||
return this_play[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_scorebug_embed(self, session: Session, full_length: bool = True, classic: bool = True) -> discord.Embed:
|
||||
gt_string = ' - Unlimited'
|
||||
if self.game_type == 'minor-league':
|
||||
gt_string = ' - Minor League'
|
||||
elif self.game_type == 'major-league':
|
||||
gt_string = ' - Major League'
|
||||
elif self.game_type == 'hall-of-fame':
|
||||
gt_string = ' - Hall of Fame'
|
||||
elif 'gauntlet' in self.game_type:
|
||||
gt_string = ' - Gauntlet'
|
||||
elif 'flashback' in self.game_type:
|
||||
gt_string = ' - Flashback'
|
||||
elif 'exhibition' in self.game_type:
|
||||
gt_string = ' - Exhibition'
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - this_game: {self} / gt_string: {gt_string}')
|
||||
|
||||
embed = discord.Embed(
|
||||
title=f'{self.away_team.sname} @ {self.home_team.sname}{gt_string}',
|
||||
color=int('a6ce39', 16)
|
||||
)
|
||||
|
||||
def current_play(self, session: Session):
|
||||
this_play = session.exec(select(Play).where(Play.game == self).order_by(Play.id.desc()).limit(1)).one()
|
||||
return this_play
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - embed: {embed}')
|
||||
|
||||
curr_play = self.current_play_or_none(session)
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - curr_play: {self}')
|
||||
|
||||
if curr_play is not None:
|
||||
embed.add_field(
|
||||
name='Game State',
|
||||
value=curr_play.scorebug_ascii,
|
||||
inline=False
|
||||
)
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - embed post gamestate: {embed}')
|
||||
|
||||
if classic:
|
||||
embed.add_field(
|
||||
name='Pitcher',
|
||||
value=curr_play.pitcher.player.name_card_link('pitching')
|
||||
)
|
||||
embed.add_field(
|
||||
name='Batter',
|
||||
value=curr_play.batter.player.name_card_link('batting')
|
||||
)
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - embed post batter: {embed}')
|
||||
|
||||
baserunner_string = ''
|
||||
if curr_play.on_first is not None:
|
||||
baserunner_string += f'On First: {curr_play.on_first.player.name_card_link}\n'
|
||||
if curr_play.on_second is not None:
|
||||
baserunner_string += f'On Second: {curr_play.on_second.player.name_card_link}\n'
|
||||
if curr_play.on_third is not None:
|
||||
baserunner_string += f'On Third: {curr_play.on_third.player.name_card_link}'
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - baserunner_string: {baserunner_string}')
|
||||
|
||||
if len(baserunner_string) > 0:
|
||||
embed.add_field(name=' ', value=' ', inline=False)
|
||||
embed.add_field(name='Baserunners', value=baserunner_string)
|
||||
embed.add_field(name='Catcher', value=curr_play.catcher.player.name_card_link)
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - embed post runners: {embed}')
|
||||
|
||||
ai_note = curr_play.ai_note
|
||||
logging.info(f'gameplay_models - Game.get_scorebug_embed - ai_note: {ai_note}')
|
||||
if len(ai_note) > 0:
|
||||
gm_name = self.home_team.gmname if self.ai_team == 'home' else self.away_team.gmname
|
||||
embed.add_field(name=f'{gm_name} will...', value=ai_note, inline=False)
|
||||
|
||||
return embed
|
||||
|
||||
# @property
|
||||
# def game_prop(self) -> str:
|
||||
@ -179,6 +244,13 @@ class PlayerBase(SQLModel):
|
||||
else:
|
||||
logging.error(f'gameplay_models - PlayerBase - batting card url not found for {self.id}. {self.description} {self.name}')
|
||||
return self.image
|
||||
|
||||
def name_card_link(self, which: Literal['pitching', 'batting']):
|
||||
if which == 'pitching':
|
||||
return f'[{self.name}]({self.p_card_url})'
|
||||
else:
|
||||
return f'[{self.name}]({self.b_card_url})'
|
||||
|
||||
|
||||
|
||||
class Player(PlayerBase, table=True):
|
||||
@ -239,6 +311,8 @@ class Lineup(SQLModel, table=True):
|
||||
card_id: int = Field(foreign_key='card.id', index=True, ondelete='CASCADE')
|
||||
card: Card = Relationship(back_populates='lineups')
|
||||
|
||||
# TODO: add function to return string value of game stats
|
||||
|
||||
|
||||
class PlayBase(SQLModel):
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
@ -290,7 +364,7 @@ class PlayBase(SQLModel):
|
||||
wpa: float = Field(default=0)
|
||||
re24: float = Field(default=0)
|
||||
|
||||
catcher_id: int | None = Field(default=None, foreign_key='lineup.id')
|
||||
catcher_id: int = Field(foreign_key='lineup.id')
|
||||
defender_id: int | None = Field(default=None, foreign_key='lineup.id')
|
||||
runner_id: int | None = Field(default=None, foreign_key='lineup.id')
|
||||
|
||||
@ -340,6 +414,78 @@ class Play(PlayBase, table=True):
|
||||
sa_relationship_kwargs=dict(foreign_keys="[Play.runner_id]")
|
||||
)
|
||||
|
||||
@property
|
||||
def scorebug_ascii(self):
|
||||
occupied = '●'
|
||||
unoccupied = '○'
|
||||
|
||||
first_base = unoccupied if not self.on_first else occupied
|
||||
second_base = unoccupied if not self.on_second else occupied
|
||||
third_base = unoccupied if not self.on_third else occupied
|
||||
half = '▲' if self.inning_half == 'Top' else '▼'
|
||||
|
||||
if self.game.active:
|
||||
inning = f'{half} {self.inning_num}'
|
||||
outs = f'{self.starting_outs} Out{"s" if self.starting_outs != 1 else ""}'
|
||||
else:
|
||||
inning = f'F/{self.inning_num if self.inning_half == "Bot" else self.inning_num - 1}'
|
||||
outs = ''
|
||||
|
||||
game_string = f'```\n' \
|
||||
f'{self.game.away_team.abbrev.replace("Gauntlet-", ""): ^5}{self.away_score: ^3} {second_base}{inning: >10}\n' \
|
||||
f'{self.game.home_team.abbrev.replace("Gauntlet-", ""): ^5}{self.home_score: ^3} {third_base} {first_base}{outs: >8}\n```'
|
||||
|
||||
return game_string
|
||||
|
||||
@property
|
||||
def pitching_ai_note(self) -> str:
|
||||
ai_note = ''
|
||||
# Holding Baserunners
|
||||
if self.starting_outs == 2 and self.on_base_code > 0:
|
||||
if self.on_base_code in [1, 2]:
|
||||
ai_note += f'- hold the runner\n'
|
||||
elif self.on_base_code in [4, 7]:
|
||||
ai_note += f'- hold the runners\n'
|
||||
elif self.on_base_code == 5:
|
||||
ai_note += f'- hold the runner on first\n'
|
||||
elif self.on_base_code == 6:
|
||||
ai_note += f'- hold the runner on second\n'
|
||||
elif self.on_base_code in [1, 5]:
|
||||
ai_note += f'- hold the runner on 1st if they have ***** auto-jump\n'
|
||||
elif self.on_base_code == 2:
|
||||
ai_note += f'- hold the runner on 2nd if safe range is 14+\n'
|
||||
|
||||
# Defensive Alignment
|
||||
if self.on_third and self.starting_outs < 2:
|
||||
if self.on_first:
|
||||
ai_note += f'- play the corners in\n'
|
||||
elif abs(self.away_score - self.home_score) <= 3:
|
||||
ai_note += f'- play the whole infield in\n'
|
||||
else:
|
||||
ai_note += f'- play the corners in\n'
|
||||
|
||||
return ai_note
|
||||
|
||||
|
||||
@property
|
||||
def batting_ai_note(self) -> str:
|
||||
ai_note = '' # TODO: migrate Manager AI to their own local model
|
||||
|
||||
return ai_note
|
||||
|
||||
@property
|
||||
def ai_note(self) -> str: # TODO: test these three functions with specific OBCs
|
||||
if self.inning_half == 'top':
|
||||
if self.game.ai_team == 'away':
|
||||
return self.batting_ai_note
|
||||
else:
|
||||
return self.pitching_ai_note
|
||||
else:
|
||||
if self.game.ai_team == 'away':
|
||||
return self.pitching_ai_note
|
||||
else:
|
||||
return self.batting_ai_note
|
||||
|
||||
|
||||
"""
|
||||
BEGIN DEVELOPMENT HELPERS
|
||||
|
||||
@ -111,6 +111,9 @@ def session_fixture():
|
||||
team_id=420,
|
||||
created=datetime.datetime.now() - datetime.timedelta(days=60)
|
||||
))
|
||||
all_players.append(Player(
|
||||
id=70, name='Player 69', cost=70*3, mlbclub='Junior All-Stars', franchise='Junior All-Stars', cardset=cardset_1, set_num=70, pos_1='SP', pos_2='DH', description='Live', created=datetime.datetime.today() - datetime.timedelta(days=60), image='player_69_pitchingcard', image2='player_69_battingcard', rarity_id=1
|
||||
))
|
||||
|
||||
for player in all_players:
|
||||
session.add(player)
|
||||
@ -153,6 +156,7 @@ def session_fixture():
|
||||
batter=all_lineups[0],
|
||||
batter_pos=all_lineups[0].position,
|
||||
pitcher=all_lineups[19],
|
||||
catcher=all_lineups[10],
|
||||
pa=1,
|
||||
so=1
|
||||
)
|
||||
@ -162,6 +166,7 @@ def session_fixture():
|
||||
batter=all_lineups[1],
|
||||
batter_pos=all_lineups[1].position,
|
||||
pitcher=all_lineups[19],
|
||||
catcher=all_lineups[10],
|
||||
starting_outs=1
|
||||
)
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import datetime
|
||||
from sqlmodel import Session
|
||||
|
||||
from in_game.gameplay_models import CACHE_LIMIT, Card, Player, Team, select, get_card_or_none
|
||||
from in_game.gameplay_queries import get_or_create_ai_card
|
||||
from in_game.gameplay_models import CACHE_LIMIT, Card, Player, Team, select
|
||||
from in_game.gameplay_queries import get_or_create_ai_card, get_card_or_none
|
||||
from factory import session_fixture
|
||||
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ def test_delete_game(session: Session):
|
||||
|
||||
def test_get_scorebug(session: Session):
|
||||
game_1 = session.get(Game, 1)
|
||||
scorebug = game_1.get_scorebug()
|
||||
scorebug = game_1.get_scorebug(session)
|
||||
|
||||
assert scorebug.title == '31 @ 400'
|
||||
assert scorebug.color.value == int('a6ce39', 16)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from in_game.gameplay_models import Play, Game
|
||||
from in_game.gameplay_models import Lineup, Play, Game
|
||||
from factory import session_fixture
|
||||
|
||||
|
||||
@ -18,6 +18,26 @@ def test_create_play(session: Session):
|
||||
|
||||
def test_get_current_play(session: Session):
|
||||
game_1 = session.get(Game, 1)
|
||||
curr_play = game_1.current_play(session)
|
||||
curr_play = game_1.current_play_or_none(session)
|
||||
|
||||
assert curr_play.play_num == 2
|
||||
assert curr_play.play_num == 2
|
||||
|
||||
|
||||
def test_scorebug_ascii(session: Session):
|
||||
new_play = Play(
|
||||
game_id=3,
|
||||
play_num=69,
|
||||
batter=session.get(Lineup, 1),
|
||||
batter_pos='DH',
|
||||
pitcher=session.get(Lineup, 20),
|
||||
catcher=session.get(Lineup, 11),
|
||||
starting_outs=1,
|
||||
inning_num=6
|
||||
)
|
||||
session.add(new_play)
|
||||
session.commit()
|
||||
|
||||
assert new_play.scorebug_ascii == '```\nNCB3 0 ○ ▼ 6\n WV4 0 ○ ○ 1 Out\n```'
|
||||
|
||||
|
||||
# TODO: test get_ai_note
|
||||
@ -58,3 +58,12 @@ def test_player_id_from_dict(session: Session):
|
||||
get_player_id_from_dict({})
|
||||
|
||||
assert str(exc_info) == "<ExceptionInfo KeyError('Player ID could not be extracted from json data') tblen=2>"
|
||||
|
||||
|
||||
def test_player_card_link(session: Session):
|
||||
player_1 = session.get(Player, 70)
|
||||
|
||||
assert player_1.b_card_url == 'player_69_battingcard'
|
||||
assert player_1.p_card_url == 'player_69_pitchingcard'
|
||||
assert player_1.name_card_link('pitching') == '[Player 69](player_69_pitchingcard)'
|
||||
assert player_1.name_card_link('batting') == '[Player 69](player_69_battingcard)'
|
||||
|
||||
@ -3,9 +3,9 @@ from sqlmodel import Session, select
|
||||
|
||||
from in_game.gameplay_models import Team, CACHE_LIMIT
|
||||
from in_game.gameplay_queries import get_team_or_none
|
||||
from factory import session_fixture, new_teams_fixture, pytest
|
||||
from factory import session_fixture, pytest
|
||||
|
||||
def test_create_team(session: Session, new_teams: list[Team]):
|
||||
def test_create_team(session: Session):
|
||||
team_31 = session.get(Team, 31)
|
||||
team_400 = session.get(Team, 400)
|
||||
team_69 = session.get(Team, 69)
|
||||
@ -19,7 +19,7 @@ def test_create_team(session: Session, new_teams: list[Team]):
|
||||
assert team_3.abbrev == 'BAL'
|
||||
|
||||
|
||||
def test_create_incomplete_team(session: Session, new_teams: list[Team]):
|
||||
def test_create_incomplete_team(session: Session):
|
||||
team_1 = Team(
|
||||
id=446, abbrev='CLS', sname='Macho Men', lname='Columbus Macho Men', gmid=181818, gmname='Mason Socc', gsheet='asdf1234', wallet=6969, team_value=69420, collection_value=169420, color='https://i.postimg.cc/8kLZCYXh/S10CLS.png', season=7, event=False, career=0
|
||||
)
|
||||
@ -32,7 +32,7 @@ def test_create_incomplete_team(session: Session, new_teams: list[Team]):
|
||||
assert str(exc_info) == "<ExceptionInfo IntegrityError('(sqlite3.IntegrityError) NOT NULL constraint failed: team.ranking') tblen=24>"
|
||||
|
||||
|
||||
async def test_team_cache(session: Session, new_teams: list[Team]):
|
||||
async def test_team_cache(session: Session):
|
||||
team_31 = session.get(Team, 31)
|
||||
team_3 = session.get(Team, 3)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user