Example #1
0
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))
Example #2
0
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))
Example #3
0
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)
Example #4
0
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)
Example #5
0
			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:
Example #6
0
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)
Example #7
0
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)
Example #8
0
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