def processMessageCoin(game, isHeads, author): log.debug("Processing coin toss message: {}".format(str(isHeads))) utils.setGamePlayed(game) if isHeads == utils.coinToss(): log.debug("User won coin toss, asking if they want to defer") game.status.waitingAction = Action.DEFER game.status.waitingOn.set(False) utils.setWaitingId(game, 'return') game.dirty = True if utils.isGameOvertime(game): questionString = "do you want to **defend** or **attack**?" else: questionString = "do you want to **receive** or **defer**?" message = "{}, {} won the toss, {}".format(string_utils.getCoachString(game, False), game.away.name, questionString) return True, string_utils.embedTableInMessage(message, utils.getActionTable(game, Action.DEFER)) else: log.debug("User lost coin toss, asking other team if they want to defer") game.status.waitingAction = Action.DEFER game.status.waitingOn.set(True) utils.setWaitingId(game, 'return') game.dirty = True if utils.isGameOvertime(game): questionString = "do you want to **defend** or **attack**?" else: questionString = "do you want to **receive** or **defer**?" message = "{}, {} won the toss, {}".format(string_utils.getCoachString(game, True), game.home.name, questionString) return True, string_utils.embedTableInMessage(message, utils.getActionTable(game, Action.DEFER))
def processMessageDefer(game, isDefer, author): log.debug("Processing defer message: {}".format(str(isDefer))) authorHomeAway = utils.coachHomeAway(game, author) utils.setGamePlayed(game) if utils.isGameOvertime(game): if isDefer: log.debug("User deferred, {} is attacking".format(authorHomeAway.negate().name())) state.setStateOvertimeDrive(game, authorHomeAway.negate()) game.status.receivingNext = authorHomeAway.copy() game.status.waitingOn.reverse() game.dirty = True utils.sendDefensiveNumberMessage(game) return True, "{} deferred and will attack next. Overtime has started!\n\n{}\n\n{}".format( game.team(authorHomeAway).name, string_utils.getCurrentPlayString(game), string_utils.getWaitingOnString(game)) else: log.debug("User elected to attack, {} is attacking".format(authorHomeAway)) state.setStateOvertimeDrive(game, authorHomeAway) game.status.receivingNext = authorHomeAway.negate() game.status.waitingOn.reverse() game.dirty = True utils.sendDefensiveNumberMessage(game) return True, "{} elected to attack. Overtime has started!\n\n{}\n\n{}".format( game.team(authorHomeAway).name, string_utils.getCurrentPlayString(game), string_utils.getWaitingOnString(game)) else: if isDefer: log.debug("User deferred, {} is receiving".format(authorHomeAway.negate())) state.setStateKickoff(game, authorHomeAway) game.status.receivingNext = authorHomeAway.copy() game.status.waitingOn.reverse() game.dirty = True utils.sendDefensiveNumberMessage(game) return True, "{} deferred and will receive the ball in the second half. The game has started!\n\n{}\n\n{}".format( game.team(authorHomeAway).name, string_utils.getCurrentPlayString(game), string_utils.getWaitingOnString(game)) else: log.debug("User elected to receive, {} is receiving".format(authorHomeAway)) state.setStateKickoff(game, authorHomeAway.negate()) game.status.receivingNext = authorHomeAway.negate() game.status.waitingOn.reverse() game.dirty = True utils.sendDefensiveNumberMessage(game) return True, "{} elected to receive. The game has started!\n\n{}\n\n{}".format( game.team(authorHomeAway).name, string_utils.getCurrentPlayString(game), string_utils.getWaitingOnString(game))
def executePunt(game, yards): log.debug("Ball punted for {} yards".format(yards)) game.status.location = game.status.location + yards if game.status.location >= 100: log.debug("Punted into the end zone, touchback") setStateTouchback(game, game.status.possession.negate()) if game.status.location > 110: return "The punt goes out the back of the end zone, touchback" else: return "The punt goes into the end zone, touchback" else: log.debug("Punt caught, setting up turnover") if utils.isGameOvertime(game): return overtimeTurnover(game) else: turnover(game) return "It's a {} yard punt".format(yards)
def getCurrentPlayString(game): bldr = [] if game.status.waitingAction == Action.CONVERSION: bldr.append("{} just scored. ".format( game.team(game.status.possession).name)) elif game.status.waitingAction == Action.KICKOFF: bldr.append("{} is kicking off. ".format( game.team(game.status.possession).name)) else: bldr.append("It's {} and {} on the {}. ".format( getDownString(game.status.down), "goal" if game.status.location + game.status.yards >= 100 else game.status.yards, getLocationString(game))) if utils.isGameOvertime(game): bldr.append("In the {}.".format(getNthWord(game.status.quarter))) else: bldr.append("{} left in the {}.".format( renderTime(game.status.clock), getNthWord(game.status.quarter))) return ''.join(bldr)
utils.clearLogGameID() for game in index.getGamesPastPlayclock(): log.debug("Game past playclock: {}".format(game.thread)) utils.cycleStatus(game, None) game.status.state(game.status.waitingOn).playclockPenalties += 1 penaltyMessage = "{} has not sent their number in over 24 hours, playclock penalty. This is their {} penalty.".format( string_utils.getCoachString(game, game.status.waitingOn), string_utils.getNthWord(game.status.state(game.status.waitingOn).playclockPenalties)) if game.status.state(game.status.waitingOn).playclockPenalties >= 3: log.debug("3 penalties, game over") result = utils.endGame(game, game.team(game.status.waitingOn.negate()).name) resultMessage = "They forfeit the game. {} has won!\n\n{}".format(string_utils.flair(game.team(game.status.waitingOn.negate())), result) elif game.status.waitingOn == game.status.possession: log.debug("Waiting on offense, turnover") if utils.isGameOvertime(game): resultMessage = state.overtimeTurnover(game) if game.status.waitingAction != Action.END: utils.sendDefensiveNumberMessage(game) else: state.turnover(game) game.status.waitingOn = game.status.possession.negate() utils.sendDefensiveNumberMessage(game) resultMessage = "Turnover, {} has the ball.".format(string_utils.flair(game.team(game.status.waitingOn))) else: log.debug("Waiting on defense, touchdown") if utils.isGameOvertime(game): state.forceTouchdown(game, game.status.possession) resultMessage = state.overtimeTurnover(game) if game.status.waitingAction != Action.END:
def processMessage(message, force=False): if isinstance(message, praw.models.Message): isMessage = True log.debug("Processing a message from /u/{} : {}".format(str(message.author), message.id)) else: isMessage = False log.debug("Processing a comment from /u/{} : {}".format(str(message.author), message.id)) response = None success = None updateWaiting = True dataTable = None if message.parent_id is not None and (message.parent_id.startswith("t1") or message.parent_id.startswith("t4")): if isMessage: parent = reddit.getMessage(message.parent_id[3:]) else: parent = reddit.getComment(message.parent_id[3:]) if parent is not None and str(parent.author).lower() == globals.ACCOUNT_NAME: dataTable = string_utils.extractTableFromMessage(parent.body) if dataTable is not None: if 'action' not in dataTable or 'thread' not in dataTable: dataTable = None else: dataTable['source'] = parent.fullname log.debug("Found a valid datatable in parent message: {}".format(str(dataTable))) body = message.body.lower() author = str(message.author) game = None appendMessageId = False if dataTable is not None: game = index.reloadAndReturn(dataTable['thread']) if game is not None: utils.cycleStatus(game, message.fullname) utils.setLogGameID(game.thread, game) waitingOn = utils.isGameWaitingOn(game, author, dataTable['action'], dataTable['source'], force) if waitingOn is not None: response = waitingOn success = False updateWaiting = False elif game.errored: log.debug("Game is errored, skipping") response = "This game is currently in an error state, /u/{} has been contacted to take a look".format( globals.OWNER) success = False updateWaiting = False else: if dataTable['action'] == Action.COIN and not isMessage: keywords = ["heads", "tails"] keyword = utils.findKeywordInMessage(keywords, body) if keyword == "heads": success, response = processMessageCoin(game, True, author) elif keyword == "tails": success, response = processMessageCoin(game, False, author) elif keyword == "mult": success = False response = "I found both {} in your message. Please reply with just one of them.".format( ' and '.join(keywords)) elif dataTable['action'] == Action.DEFER and not isMessage: if utils.isGameOvertime(game): keywords = ["defend", "attack"] else: keywords = ["defer", "receive"] keyword = utils.findKeywordInMessage(keywords, body) if keyword == "defer" or keyword == "defend": success, response = processMessageDefer(game, True, author) elif keyword == "receive" or keyword == "attack": success, response = processMessageDefer(game, False, author) elif keyword == "mult": success = False response = "I found both {} in your message. Please reply with just one of them.".format( ' and '.join(keywords)) elif dataTable['action'] in classes.playActions and isMessage: success, response = processMessageDefenseNumber(game, body, author) appendMessageId = not success elif dataTable['action'] in classes.playActions and not isMessage: success, response = processMessageOffensePlay(game, body, author) else: log.debug("Couldn't get a game for /u/{}".format(author)) else: log.debug("Parsing non-datatable message") if isMessage and str(message.author).lower() in wiki.admins: if body.startswith("newgame"): response = processMessageNewGame(message.body, str(message.author)) elif body.startswith("kick"): response = processMessageKickGame(message.body) elif body.startswith("pause"): response = processMessagePauseGame(message.body) elif body.startswith("abandon"): response = processMessageAbandonGame(message.body) elif body.startswith("status"): response = processMessageGameStatus(message.body) elif body.startswith("reindex"): response = processMessageReindex(message.body) elif body.startswith("chew"): response = processMessageDefaultChew(message.body) elif body.startswith("gamelist"): response = processMessageGameList(message.body) message.mark_read() if response is not None: if success is not None and not success and dataTable is not None and string_utils.extractTableFromMessage( response) is None: log.debug("Embedding datatable in reply on failure") response = string_utils.embedTableInMessage(response, dataTable) if updateWaiting and game is not None: if appendMessageId: utils.addWaitingId(game, 'return') else: utils.setWaitingId(game, 'return') resultMessage = reddit.replyMessage(message, response) if resultMessage is None: log.warning("Could not send message") elif game is not None and 'return' in game.status.waitingId: if appendMessageId: utils.clearReturnWaitingId(game) utils.addWaitingId(game, resultMessage.fullname) else: utils.setWaitingId(game, resultMessage.fullname) game.dirty = True log.debug("Message/comment replied, now waiting on: {}".format(game.status.waitingId)) else: if isMessage: log.debug("Couldn't understand message") resultMessage = reddit.replyMessage(message, "I couldn't understand your message, please try again or message /u/Watchful1 if you need help.") if resultMessage is None: log.warning("Could not send message") if game is not None and game.dirty: log.debug("Game is dirty, updating thread") utils.updateGameThread(game)
def executePlay(game, play, number, timeOption): startingPossessionHomeAway = game.status.possession.copy() actualResult = None result = None yards = None resultMessage = "Something went wrong, I should never have reached this" diffMessage = None success = True timeMessage = None playSummary = PlaySummary() playSummary.down = game.status.down playSummary.toGo = game.status.yards playSummary.location = game.status.location playSummary.offNum = number playSummary.posHome = game.status.possession.isHome runoffResult, timeMessageBetweenPlay, timeBetweenPlay = betweenPlayRunoff(game, play, startingPossessionHomeAway, timeOption) if runoffResult == RunStatus.STOP_QUARTER: log.debug("Hit stop_quarter, not running play") else: if play in classes.conversionPlays: numberResult, diffMessage, defenseNumber = getNumberDiffForGame(game, number) playSummary.defNum = defenseNumber log.debug("Executing conversion play: {}".format(play)) result = getPlayResult(game, play, numberResult) actualResult = result['result'] if result['result'] == Result.TWO_POINT: log.debug("Successful two point conversion") resultMessage = "The two point conversion is successful" scoreTwoPoint(game, game.status.possession) if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: setStateKickoff(game, game.status.possession) elif result['result'] == Result.PAT: log.debug("Successful PAT") resultMessage = "The PAT was successful" scorePAT(game, game.status.possession) if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: setStateKickoff(game, game.status.possession) elif result['result'] == Result.KICKOFF: log.debug("Attempt unsuccessful") if play == Play.TWO_POINT: resultMessage = "The two point conversion attempt was unsuccessful" elif play == Play.PAT: resultMessage = "The PAT attempt was unsuccessful" else: resultMessage = "Conversion unsuccessful" if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: setStateKickoff(game, game.status.possession) elif result['result'] == Result.TURNOVER_PAT: log.debug("Turnover PAT") resultMessage = "The attempt was fumbled and run all the way back! Two points {}!".format(game.team(game.status.possession.negate()).name) scoreTwoPoint(game, game.status.possession.negate()) if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: setStateKickoff(game, game.status.possession) game.status.defensiveNumber = None elif play in classes.kickoffPlays: numberResult, diffMessage, defenseNumber = getNumberDiffForGame(game, number) playSummary.defNum = defenseNumber log.debug("Executing kickoff play: {}".format(play)) result = getPlayResult(game, play, numberResult) actualResult = result['result'] if result['result'] == Result.KICK: if 'yards' not in result: log.warning("Result is a successful kick, but I couldn't find any yards") resultMessage = "Result of kick is a number of yards, but something went wrong and I couldn't find what number" success = False else: log.debug("Result is a kick of {} yards".format(result['yards'])) yards = result['yards'] game.status.location = game.status.location + yards if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: turnover(game) resultMessage = "{} yard kick.".format(yards) elif result['result'] == Result.GAIN: if 'yards' not in result: log.warning("Result is a dropped kick, but I couldn't find any yards") resultMessage = "The receiver drops the kick, but something went wrong and I couldn't find where" success = False else: log.debug("Result is a dropped kick of {} yards".format(result['yards'])) yards = result['yards'] game.status.location = game.status.location + yards resultMessage = "It's dropped! Recovered by {} on the {}".format(game.team(game.status.possession).name, string_utils.getLocationString(game)) game.status.waitingAction = Action.PLAY elif result['result'] == Result.TOUCHBACK: log.debug("Result is a touchback") setStateTouchback(game, game.status.possession.negate()) resultMessage = "The kick goes into the end zone, touchback." elif result['result'] == Result.TOUCHDOWN: log.debug("Result is a touchdown") resultMessage = "It's dropped! The kicking team recovers and runs it into the end zone! Touchdown {}!".format(game.team(game.status.possession).name) scoreTouchdown(game, game.status.possession) elif result['result'] == Result.TURNOVER_TOUCHDOWN: log.debug("Result is a run back for touchdown") resultMessage = "It's run all the way back! Touchdown {}!".format(game.team(game.status.possession.negate()).name) scoreTouchdown(game, game.status.possession.negate()) elif play in classes.normalPlays: numberResult, diffMessage, defenseNumber = getNumberDiffForGame(game, number) playSummary.defNum = defenseNumber log.debug("Executing normal play: {}".format(play)) result = getPlayResult(game, play, numberResult) if play == Play.FIELD_GOAL: utils.addStat(game, 'fieldGoalsAttempted', 1) actualResult = result['result'] if play == Play.PUNT and result['result'] == Result.GAIN and game.status.location + result['yards'] >= 100: result['result'] = Result.PUNT actualResult = Result.PUNT if result['result'] == Result.GAIN: if play == Play.PUNT: log.debug("Muffed punt. Ball moved from {} to {}".format(game.status.location, game.status.location + result['yards'])) game.status.location = game.status.location + result['yards'] game.status.yards = 10 game.status.down = 1 yards = result['yards'] resultMessage = "The receiver drops the ball! {} recovers on the {}.".format(game.team(game.status.possession).name, string_utils.getLocationString(game)) else: if 'yards' not in result: log.warning("Result is a gain, but I couldn't find any yards") resultMessage = "Result of play is a number of yards, but something went wrong and I couldn't find what number" success = False else: log.debug("Result is a gain of {} yards".format(result['yards'])) gainResult, yards, resultMessage = executeGain(game, play, result['yards']) if gainResult != Result.ERROR: if yards is not None: actualResult = gainResult else: success = False elif result['result'] == Result.INCOMPLETE: log.debug("Result is an incomplete pass") actualResult, yards, resultMessage = executeGain(game, play, 0, True) elif result['result'] == Result.TOUCHDOWN: log.debug("Result is a touchdown") resultMessage = "It's a {} into the endzone! Touchdown {}!".format(play.name.lower(), game.team(game.status.possession).name) previousLocation = game.status.location utils.addStatRunPass(game, play, 100 - previousLocation) scoreTouchdown(game, game.status.possession) yards = 100 - previousLocation elif result['result'] == Result.FIELD_GOAL: log.debug("Result is a field goal") resultMessage = "The {} yard field goal is good!".format(100 - game.status.location + 17) utils.addStat(game, 'fieldGoalsScored', 1) scoreFieldGoal(game, game.status.possession) if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: setStateKickoff(game, game.status.possession) elif result['result'] == Result.PUNT: if 'yards' not in result: log.warning("Result is a punt, but I couldn't find any yards") resultMessage = "Result of play is a successful punt, but something went wrong and I couldn't find how long a punt" else: log.debug("Successful punt of {} yards".format(result['yards'])) if utils.isGameOvertime(game): log.warning("A punt happened in overtime, this shouldn't have happened") resultMessage = "A punt happened, but it's overtime. This shouldn't be possible." else: resultMessage = executePunt(game, result['yards']) yards = result['yards'] elif result['result'] in [Result.TURNOVER, Result.MISS]: log.debug("Play results in a turnover") if play == Play.RUN: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "Fumble! The ball is dropped, {} recovers!".format(game.team(game.status.possession.negate()).name) elif play == Play.PASS: utils.addStat(game, 'turnoverInterceptions', 1) resultMessage = "Picked off! The pass is intercepted, {} ball!".format(game.team(game.status.possession.negate()).name) elif play == Play.FIELD_GOAL: if result['result'] == Result.TURNOVER: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "It's blocked!" else: resultMessage = "The kick is wide." elif play == Play.PUNT: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "It's blocked!" else: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "It's a turnover!" if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: turnover(game) elif result['result'] == Result.TURNOVER_TOUCHDOWN: log.debug("Play results in a turnover and run back") if play == Play.RUN: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "Fumble! The ball is dropped and it's run all the way back. Touchdown {}!".format(game.team(game.status.possession.negate()).name) elif play == Play.PASS: utils.addStat(game, 'turnoverInterceptions', 1) resultMessage = "Picked off! The pass is intercepted and it's run all the way back. Touchdown {}!".format(game.team(game.status.possession.negate()).name) elif play == Play.FIELD_GOAL: resultMessage = "It's blocked! The ball is picked up and run all the way back. Touchdown {}!".format(game.team(game.status.possession.negate()).name) elif play == Play.PUNT: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "The punt is returned all the way! Touchdown {}!".format(game.team(game.status.possession.negate()).name) else: utils.addStat(game, 'turnoverFumble', 1) resultMessage = "It's a turnover and run back for a touchdown!" yards = game.status.location scoreTouchdown(game, game.status.possession.negate()) if utils.isGameOvertime(game): output = utils.endGame(game, game.team(game.status.possession).name) timeMessage = "Game over! {} wins!\n\n{}".format(string_utils.flair(game.team(game.status.possession)), output) game.status.defensiveNumber = None elif play in classes.timePlays: if play == Play.KNEEL: log.debug("Running kneel play") actualResult = Result.KNEEL game.status.down += 1 if game.status.down > 4: log.debug("Turnover on downs") if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: turnover(game) resultMessage = "Turnover on downs" else: resultMessage = "The quarterback takes a knee" elif play == Play.SPIKE: log.debug("Running spike play") actualResult = Result.SPIKE game.status.down += 1 if game.status.down > 4: log.debug("Turnover on downs") if utils.isGameOvertime(game): timeMessage = overtimeTurnover(game) else: turnover(game) resultMessage = "Turnover on downs" else: resultMessage = "The quarterback spikes the ball" result = {'result': actualResult} else: log.debug("Something went wrong, invalid play: {}".format(play)) resultMessage = "Something went wrong, invalid play: {}".format(play) success = False if runoffResult == RunStatus.STOP_QUARTER: messages = [] else: messages = [resultMessage] timeOffClock = None if actualResult is not None and game.status.quarterType == QuarterType.NORMAL: if timeMessage is None: timeMessage, timeOffClock = updateTime(game, play, result['result'], actualResult, yards, startingPossessionHomeAway, timeOption, timeBetweenPlay) if timeMessageBetweenPlay is not None: messages.append(timeMessageBetweenPlay) if timeMessage is not None: messages.append(timeMessage) messages.append("{}\n\n".format( string_utils.getCurrentPlayString(game) )) if diffMessage is not None: messages.append(diffMessage) playSummary.play = play playSummary.result = result['result'] if result is not None else None playSummary.actualResult = actualResult if actualResult in [Result.TURNOVER]: playSummary.yards = None else: playSummary.yards = yards playSummary.time = timeOffClock if success: game.status.plays.append(playSummary) messages.append(string_utils.getCoachString(game, game.status.waitingOn.negate())) return success, '\n\n'.join(messages)
def executeGain(game, play, yards, incomplete=False): if play not in classes.movementPlays and play not in [Play.PUNT]: log.warning("This doesn't look like a valid movement play: {}".format(play)) return Result.ERROR, None, "Something went wrong trying to move the ball" previousLocation = game.status.location log.debug("Ball moved from {} to {}".format(previousLocation, previousLocation + yards)) game.status.location = previousLocation + yards if game.status.location >= 100: log.debug("Ball passed the line, touchdown offense") utils.addStatRunPass(game, play, 100 - previousLocation) scoreTouchdown(game, game.status.possession) return Result.TOUCHDOWN, 100 - previousLocation, "{} with a {} yard {} into the end zone for a touchdown!".format(game.team(game.status.possession).name, yards, play.name.lower()) elif game.status.location <= 0: log.debug("Ball went back over the line, safety for the defense") utils.addStatRunPass(game, play, previousLocation * -1) scoreSafety(game, game.status.possession.negate()) if play == Play.RUN: resultMessage = "The runner is taken down in the end zone for a safety." elif play == Play.PASS: resultMessage = "Sack! The quarterback is taken down in the endzone for a safety." else: resultMessage = "It's a safety!" return Result.SAFETY, 0 - previousLocation, resultMessage else: log.debug("Ball moved, but didn't enter an endzone, checking and updating play status") utils.addStatRunPass(game, play, yards) yardsRemaining = game.status.yards - yards if yardsRemaining <= 0: log.debug("First down") game.status.yards = 10 game.status.down = 1 return Result.GAIN, game.status.location - previousLocation, "{} play for {} yard(s), first down".format(play.name.lower().capitalize(), yards) else: log.debug("Not a first down, incrementing down") game.status.down += 1 if game.status.down > 4: log.debug("Turnover on downs") if incomplete: resultMessage = "The pass is incomplete. Turnover on downs" else: resultMessage = "{} play for {} yard(s), but that's not enough for the first down. Turnover on downs".format(play.name.lower().capitalize(), yards) if utils.isGameOvertime(game): resultMessage = "{}\n\n{}".format(resultMessage, overtimeTurnover(game)) else: turnover(game) return Result.TURNOVER, game.status.location - previousLocation, resultMessage else: log.debug("Now {} down and {}".format(string_utils.getDownString(game.status.down), yardsRemaining)) game.status.yards = yardsRemaining if incomplete: resultMessage = "The pass is incomplete. {} and {}".format(string_utils.getDownString(game.status.down), yardsRemaining) else: resultMessage = "{} play for {} yard(s), {} and {}".format( play.name.lower().capitalize(), yards, string_utils.getDownString(game.status.down), "goal" if game.status.location + yardsRemaining >= 100 else yardsRemaining) return Result.GAIN, game.status.location - previousLocation, resultMessage