<commit_before>#include "cbase.h"
#include "match_ball.h"
#include "team.h"
#include "ios_replaymanager.h"

extern ConVar
	sv_ball_bodypos_keeperhands,
	sv_ball_chargedshot_minstrength,
	sv_ball_chargedshot_maxstrength,
	sv_ball_keepershot_minangle,
	sv_ball_maxplayerfinddist,
	sv_ball_keeperthrow_strength,
	sv_ball_slidezstart,
	sv_ball_slidezend,
	sv_ball_slidesidereach_ball,
	sv_ball_slideforwardreach_ball,
	sv_ball_slidebackwardreach_ball,
	sv_ball_keeperthrow_minpostdelay;

ConVar
	sv_ball_statetransition_postmessagedelay_short			("sv_ball_statetransition_postmessagedelay_short",			"0.1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_postmessagedelay_normal			("sv_ball_statetransition_postmessagedelay_normal",			"1.25",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_postmessagedelay_long			("sv_ball_statetransition_postmessagedelay_long",			"2.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_messagedelay_normal				("sv_ball_statetransition_messagedelay_normal",				"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_messagedelay_short				("sv_ball_statetransition_messagedelay_short",				"0.1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_yellowcardballdist_forward						("sv_ball_yellowcardballdist_forward",						"70",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_yellowcardballdist_backward						("sv_ball_yellowcardballdist_backward",						"70",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalreplay_count								("sv_ball_goalreplay_count",								"2",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalreplay_delay								("sv_ball_goalreplay_delay",								"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_pass_mindist								("sv_ball_stats_pass_mindist",								"300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_clearance_minspeed						("sv_ball_stats_clearance_minspeed",						"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_shot_mindist								("sv_ball_stats_shot_mindist",								"270",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_save_minspeed								("sv_ball_stats_save_minspeed",								"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_assist_maxtime							("sv_ball_stats_assist_maxtime",							"8",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_duration_freekick						("sv_ball_advantage_duration_freekick",						"3",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_ignore_duration_freekick				("sv_ball_advantage_ignore_duration_freekick",				"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_duration_penalty						("sv_ball_advantage_duration_penalty",						"1.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_ignore_duration_penalty				("sv_ball_advantage_ignore_duration_penalty",				"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_offsidedist										("sv_ball_offsidedist",										"60",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalcelebduration								("sv_ball_goalcelebduration",								"8.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_setpiece_close_time								("sv_ball_setpiece_close_time",								"0.75",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_setpiece_close_dist								("sv_ball_setpiece_close_dist",								"75",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_doubletouchfouls								("sv_ball_doubletouchfouls",								"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_player_secondyellowcard_banduration				("sv_ball_player_secondyellowcard_banduration",				"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_player_redcard_banduration						("sv_ball_player_redcard_banduration",						"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickdist_owngoal							("sv_ball_freekickdist_owngoal",							"850",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickdist_opponentgoal						("sv_ball_freekickdist_opponentgoal",						"1300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickangle_opponentgoal						("sv_ball_freekickangle_opponentgoal",						"60",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_closetogoaldist									("sv_ball_closetogoaldist",									"1300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedshotblocktime_freekick					("sv_ball_chargedshotblocktime_freekick",					"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedshotblocktime_corner						("sv_ball_chargedshotblocktime_corner",						"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_shotsblocktime_penalty							("sv_ball_shotsblocktime_penalty",							"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slidesidereach_foul								("sv_ball_slidesidereach_foul",								"10",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slideforwardreach_foul							("sv_ball_slideforwardreach_foul",							"25",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slidebackwardreach_foul							("sv_ball_slidebackwardreach_foul",							"20",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_powerthrow_strength								("sv_ball_powerthrow_strength",								"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedthrow_minstrength						("sv_ball_chargedthrow_minstrength",						"450",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedthrow_maxstrength						("sv_ball_chargedthrow_maxstrength",						"990",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_timelimit_setpiece								("sv_ball_timelimit_setpiece",								"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_timelimit_remotecontrolled						("sv_ball_timelimit_remotecontrolled",						"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throwin_minangle								("sv_ball_throwin_minangle",								"-5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throwin_minstrength								("sv_ball_throwin_minstrength",								"270",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_foulcheckdelay									("sv_ball_foulcheckdelay",									"2.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_foulcheckmaxdist								("sv_ball_foulcheckmaxdist",								"200",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_kickoff_strength								("sv_ball_kickoff_strength",								"350",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_kickoff_minpostdelay							("sv_ball_kickoff_minpostdelay",							"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throw_minpostdelay								("sv_ball_throw_minpostdelay",								"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY);



LINK_ENTITY_TO_CLASS( match_ball, CMatchBall );

BEGIN_DATADESC(	CMatchBall )
END_DATADESC()

IMPLEMENT_SERVERCLASS_ST( CMatchBall, DT_MatchBall )
	SendPropEHandle(SENDINFO(m_pLastActivePlayer)),
	SendPropInt(SENDINFO(m_nLastActiveTeam)),
END_SEND_TABLE()

CMatchBall *g_pMatchBall = NULL;

CMatchBall *CreateMatchBall(const Vector &pos)
{
	if (!g_pMatchBall)
		g_pMatchBall = static_cast<CMatchBall *>(CreateEntityByName("match_ball"));

	g_pMatchBall->SetAbsOrigin(pos);
	g_pMatchBall->Spawn();
	g_pMatchBall->SetPos(pos);

	return g_pMatchBall;
}

CMatchBall *GetMatchBall()
{
	return g_pMatchBall;
}

CMatchBall::CMatchBall()
{
	m_pLastActivePlayer = NULL;
	m_nLastActiveTeam = TEAM_NONE;
	m_pPossessingPl = NULL;
	m_nPossessingTeam = TEAM_NONE;
	m_flPossessionStart = -1;
	m_ePenaltyState = PENALTY_NONE;
	m_bIsAdvantage = false;
	m_bBallInAirAfterThrowIn = false;
	m_flStateTimelimit = -1;
}

CMatchBall::~CMatchBall()
{
	g_pMatchBall = NULL;
}

void CMatchBall::Spawn()
{
	//TODO: Move the ball skin parsing to a better spot
	CBallInfo::ParseBallSkins();
	
	CBall::Spawn();
}

void CMatchBall::Reset()
{
	CBall::Reset();

	m_pLastActivePlayer = NULL;
	m_pSetpieceTaker = NULL;
	m_flStateLeaveTime = gpGlobals->curtime;
	m_flNextStateMessageTime = -1;
	m_pOtherPl = NULL;
	m_pPossessingPl = NULL;
	m_nPossessingTeam = TEAM_NONE;
	m_flPossessionStart = -1;
	m_ePenaltyState = PENALTY_NONE;
	m_bIsAdvantage = false;
	m_bBallInAirAfterThrowIn = false;
	m_flStateTimelimit = -1;

	UnmarkOffsidePlayers();
	RemoveAllTouches();
}

void CMatchBall::State_Transition(ball_state_t nextState, float nextStateMessageDelay /*= 0*/, float nextStatePostMessageDelay /*= 0*/, bool cancelQueuedState /*= false*/)
{
	if (nextState != BALL_STATE_KEEPERHANDS)
		m_bIsAdvantage = false;

	if (nextState != BALL_STATE_NORMAL)
		m_bBallInAirAfterThrowIn = false;

	if (nextStateMessageDelay == 0 && nextStatePostMessageDelay == 0)
	{
		State_Leave(nextState);
		State_Enter(nextState, cancelQueuedState);
	}
	else
	{
		m_eNextState = nextState;
		m_flNextStateMessageTime = gpGlobals->curtime + nextStateMessageDelay;
		m_flStateLeaveTime = gpGlobals->curtime + nextStateMessageDelay + nextStatePostMessageDelay;
		m_bHasQueuedState = true;

		if (State_Get() != BALL_STATE_GOAL)
			SDKGameRules()->AddBallStateTransitionTime(nextStateMessageDelay + nextStatePostMessageDelay);
	}
}

void CMatchBall::State_Enter(ball_state_t newState, bool cancelQueuedState)
{
	if (cancelQueuedState)
	{
		m_eNextState = BALL_STATE_NONE;
		m_bHasQueuedState = false;
	}

	m_eBallState = newState;
	m_pCurStateInfo = State_LookupInfo( newState );

	m_flStateEnterTime = gpGlobals->curtime;
	m_flStateTimelimit = -1;
	m_flNextStateMessageTime = -1;

	m_pPl = NULL;
	m_pOtherPl = NULL;
	m_pSetpieceTaker = NULL;

	IGameEvent *pEvent = gameeventmanager->CreateEvent("ball_state");
	if (pEvent)
	{
		pEvent->SetInt("state", State_Get());
		gameeventmanager->FireEvent(pEvent);
	}

	// Initialize the new state.
	if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
	{
		(this->*m_pCurStateInfo->pfnEnterState)();
	}

	//State_Think();
}

void CMatchBall::State_Leave(ball_state_t newState)
{
	SDKGameRules()->DisableShield();

	if (CSDKPlayer::IsOnField(m_pPl))
	{
		m_pPl->SetChargedshotBlocked(false);
		m_pPl->SetShotsBlocked(false);
	}

	if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
	{
		(this->*m_pCurStateInfo->pfnLeaveState)(newState);
	}
}

void CMatchBall::State_Think()
{
	m_pPhys->GetPosition(&m_vPos, &m_aAng);
	m_pPhys->GetVelocity(&m_vVel, &m_vRot);

	CheckFieldZone();
	CheckPenBoxPosition();

	if (m_eNextState != BALL_STATE_NONE)
	{
		if (m_flNextStateMessageTime != -1 && gpGlobals->curtime >= m_flNextStateMessageTime && m_eNextState != BALL_STATE_KICKOFF)
		{
			SendNotifications();
			m_flNextStateMessageTime = -1;
		}
		else if (gpGlobals->curtime >= m_flStateLeaveTime)
		{
			State_Leave(m_eNextState);
			State_Enter(m_eNextState, true);
			return;
		}
	}

	if (State_Get() == BALL_STATE_THROWIN || State_Get() == BALL_STATE_CORNER || State_Get() == BALL_STATE_GOALKICK || State_Get() == BALL_STATE_KICKOFF)
	{
		if (SDKGameRules()->CheckTimeout())
			m_flStateTimelimit = -1;
	}

	if (m_pCurStateInfo
		&& State_Get() != BALL_STATE_NORMAL
		&& m_eNextState == BALL_STATE_NONE
		&& CSDKPlayer::IsOnField(m_pPl)
		&& m_flStateTimelimit != -1
		&& gpGlobals->curtime >= m_flStateTimelimit) // Player is afk or timed out
	{
		m_pPl->SetDesiredTeam(TEAM_SPECTATOR, m_pPl->GetTeamNumber(), 0, true, false, false);
	}

	if (m_pCurStateInfo && m_pCurStateInfo->pfnThink)
	{	
		(this->*m_pCurStateInfo->pfnThink)();
	}

	if (m_pPl) // Set info for the client
	{
		m_pLastActivePlayer = m_pPl;
		m_nLastActiveTeam = m_pPl->GetTeamNumber();
	}
}

void CMatchBall::State_STATIC_Enter()
{
	SDKGameRules()->StopMeteringClockStoppedTime();
}

void CMatchBall::State_STATIC_Think()
{
}

void CMatchBall::State_STATIC_Leave(ball_state_t newState)
{
	if (!SDKGameRules()->IsIntermissionState())
		SDKGameRules()->StartMeteringClockStoppedTime();
}

void CMatchBall::State_NORMAL_Enter()
{
	m_pPhys->EnableMotion(true);
	EnablePlayerCollisions(true);
	m_pPhys->Wake();
	SDKGameRules()->StopMeteringClockStoppedTime();
	//SetMatchEvent(MATCH_EVENT_NONE);
	//SetMatchSubEvent(MATCH_EVENT_NONE);
}

void CMatchBall::State_NORMAL_Think()
{
	if (m_eNextState == BALL_STATE_GOAL)
		return;

	if (SDKGameRules()->State_Get() == MATCH_PERIOD_PENALTIES)
	{
		if (m_ePenaltyState == PENALTY_KICKED && !CheckGoal() && !CheckGoalLine())
		{
			m_pPl = GetGlobalTeam(m_nFoulingTeam)->GetPlayerByPosType(POS_GK);

			if (m_pPl && (m_pPl->IsShooting() || m_pPl->IsKeeperDiving()))
			{
				UpdateCarrier();
				DoBodyPartAction();
			}
		}

		return;
	}

	if (!SDKGameRules()->IsIntermissionState() && !m_bHasQueuedState)
	{
		CheckAdvantage();

		if (!CheckOffside())
		{
			if (!CheckGoal())
			{
				if (!CheckGoalLine())
				{
					CheckSideline();
				}
			}
		}
	}

	for (int ignoredPlayerBits = 0;;)
	{
		m_pPl = FindNearestPlayer(TEAM_NONE, FL_POS_ANY, false, ignoredPlayerBits, sv_ball_maxplayerfinddist.GetFloat());

		if (!m_pPl)
			return;

		UpdateCarrier();

		// The current player was able to perform an action, so exit the loop
		if (DoBodyPartAction())
			break;

		// Exclude the current player from subsequent checks
		ignoredPlayerBits |= (1 << (m_pPl->entindex() - 1));

		m_pPl = NULL;
	}
}

void CMatchBall::State_NORMAL_Leave(ball_state_t newState)
{
	UnmarkOffsidePlayers();
	UpdatePossession(NULL);

	if (!SDKGameRules()->IsIntermissionState())
		SDKGameRules()->StartMeteringClockStoppedTime();
}

void CMatchBall::State_THROWIN_Enter()
{
	EnablePlayerCollisions(false);
}

void CMatchBall::State_THROWIN_Think()
{
	Vector groundPos = Vector(m_vTriggerTouchPos.x < SDKGameRules()->m_vKickOff.GetX() ? SDKGameRules()->m_vFieldMin.GetX() - BALL_PHYS_RADIUS - 15 : SDKGameRules()->m_vFieldMax.GetX() + BALL_PHYS_RADIUS + 15, m_vTriggerTouchPos.y, SDKGameRules()->m_vKickOff.GetZ());

	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		SetPos(groundPos);

		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
		{
			SetPos(groundPos + Vector(30 * Sign(SDKGameRules()->m_vKickOff.GetX() - m_vTriggerTouchPos.x), 0, 0));
			return State_Transition(BALL_STATE_NORMAL);
		}

		SDKGameRules()->EnableShield(SHIELD_THROWIN, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(groundPos, true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		SetPos(groundPos + Vector(0, 0, m_pPl->GetPlayerMaxs().z + 2));
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_THROWIN);
		m_pPl->SetShotButtonsReleased(false);
		m_pPl->SetShotsBlocked(false);
	}

	UpdateCarrier();

	if (m_pPl->ShotButtonsReleased() && m_pPl->IsChargedshooting())
	{
		QAngle ang = m_aPlAng;

		ang[PITCH] = min(sv_ball_throwin_minangle.GetFloat(), m_aPlAng[PITCH]);

		Vector dir;
		AngleVectors(ang, &dir);
		float strength = GetChargedshotStrength(GetPitchCoeff(), sv_ball_chargedthrow_minstrength.GetInt(), sv_ball_chargedthrow_maxstrength.GetInt());

		Vector vel = dir * max(strength, sv_ball_throwin_minstrength.GetInt());

		m_pPl->AddThrowIn();
		RemoveAllTouches();
		SetVel(vel, 0, FL_SPIN_FORCE_NONE, BODY_PART_HANDS, false, sv_ball_throw_minpostdelay.GetFloat(), true);
		m_bBallInAirAfterThrowIn = true;
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_THROWIN_Leave(ball_state_t newState)
{
	if (CSDKPlayer::IsOnField(m_pPl))
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_THROW);

	EnablePlayerCollisions(true);
}

void CMatchBall::State_KICKOFF_Enter()
{
	for (int i = 1; i <= gpGlobals->maxClients; i++) 
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		pPl->m_Shared.SetStamina(100);
	}

	SetPos(SDKGameRules()->m_vKickOff);
}

void CMatchBall::State_KICKOFF_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, SDKGameRules()->GetKickOffTeam()))
	{
		m_pPl = NULL;

		m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_RIGHT);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_RIGHT);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_RIGHT);

		if (!m_pPl)
		{
			if (SDKGameRules()->m_nShieldType != SHIELD_KICKOFF)
				SDKGameRules()->EnableShield(SHIELD_KICKOFF, GetGlobalTeam(TEAM_HOME)->GetTeamNumber(), SDKGameRules()->m_vKickOff);

			if (!CSDKPlayer::PlayersAtTargetPos())
				return;

			return State_Transition(BALL_STATE_NORMAL);
		}

		SDKGameRules()->EnableShield(SHIELD_KICKOFF, m_pPl->GetTeamNumber(), SDKGameRules()->m_vKickOff);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x - m_pPl->GetTeam()->m_nRight * 30, m_vPos.y, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);

		EmitSound("Ball.Whistle");

		IGameEvent *pEvent = gameeventmanager->CreateEvent("kickoff");
		if (pEvent)
		{
			pEvent->SetInt("team", m_pPl->GetTeamNumber());
			gameeventmanager->FireEvent(pEvent);
		}
	}

	if (!CSDKPlayer::IsOnField(m_pOtherPl, SDKGameRules()->GetKickOffTeam()) || m_pOtherPl == m_pPl)
	{
		m_pOtherPl = NULL;

		m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (m_pOtherPl)
		{
			m_pOtherPl->SetPosInsideShield(Vector(m_vPos.x + m_pPl->GetTeam()->m_nRight * 100, m_vPos.y, SDKGameRules()->m_vKickOff.GetZ()), true);
		}
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	for (int i = 1; i <= gpGlobals->maxClients; i++) 
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		if (pPl->GetFlags() & FL_ATCONTROLS)
		{
			if (pPl != m_pPl && pPl != m_pOtherPl)
				pPl->RemoveFlag(FL_ATCONTROLS);
		}
	}

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->SetShotButtonsReleased(false);
		m_pPl->SetShotsBlocked(false);
	}

	UpdateCarrier();

	if (m_pPl->ShotButtonsReleased() && m_pPl->IsShooting())
	{
		RemoveAllTouches();
		SetVel(m_vPlForward2D * sv_ball_kickoff_strength.GetInt(), 0, FL_SPIN_FORCE_NONE, BODY_PART_FEET, false, sv_ball_kickoff_minpostdelay.GetFloat(), true);
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_BLANK);
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		if (m_pOtherPl)
			m_pOtherPl->RemoveFlag(FL_ATCONTROLS);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_KICKOFF_Leave(ball_state_t newState)
{
}

void CMatchBall::State_GOALKICK_Enter()
{
	Vector ballPos;

	CTeam *pTeam = GetGlobalTeam(LastOppTeam(false));

	if (Sign(m_vTriggerTouchPos.x - SDKGameRules()->m_vKickOff.GetX()) == pTeam->m_nRight)
		ballPos = pTeam->m_vGoalkickRight;
	else
		ballPos = pTeam->m_vGoalkickLeft;

	SetPos(ballPos);
}

void CMatchBall::State_GOALKICK_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = GetGlobalTeam(LastOppTeam(false))->GetPlayerByPosType(POS_GK);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_GOALKICK, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x, m_vPos.y - 100 * m_pPl->GetTeam()->m_nForward, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->SetShotsBlocked(false);
		m_pPl->SetShotButtonsReleased(false);
	}

	if (IsPlayerClose())
	{
		if (m_flSetpieceCloseStartTime == -1)
			m_flSetpieceCloseStartTime = gpGlobals->curtime;
	}
	else
		m_flSetpieceCloseStartTime = -1;

	if (m_flSetpieceCloseStartTime != -1 && gpGlobals->curtime > m_flSetpieceCloseStartTime + sv_ball_setpiece_close_time.GetFloat())
	{
		m_pPl->SetChargedshotBlocked(true);
	}
	else
		m_pPl->SetChargedshotBlocked(false);

	if (!m_pPl->ShotsBlocked()
		&& m_pPl->ShotButtonsReleased()
		&& CanReachBallStandingXY()
		&& (m_pPl->IsNormalshooting() || !m_pPl->ChargedshotBlocked() && m_pPl->IsChargedshooting()))
	{
		m_pPl->AddGoalKick();
		RemoveAllTouches();
		DoGroundShot(false);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_GOALKICK_Leave(ball_state_t newState)
{
}

void CMatchBall::State_CORNER_Enter()
{
	Vector ballPos;
	CTeam *pTeam = GetGlobalTeam(LastTeam(false));

	if (Sign(m_vTriggerTouchPos.x - SDKGameRules()->m_vKickOff.GetX()) == pTeam->m_nRight)
		ballPos = pTeam->m_vCornerRight;
	else
		ballPos = pTeam->m_vCornerLeft;
	
	SetPos(ballPos);
}

void CMatchBall::State_CORNER_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_CORNER, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x - 25 * Sign((SDKGameRules()->m_vKickOff - m_vPos).x), m_vPos.y - 25 * Sign((SDKGameRules()->m_vKickOff - m_vPos).y), SDKGameRules()->m_vKickOff[2]), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();
	
	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->SetShotsBlocked(false);
		m_pPl->SetShotButtonsReleased(false);
	}

	if (IsPlayerClose())
	{
		if (m_flSetpieceCloseStartTime == -1)
			m_flSetpieceCloseStartTime = gpGlobals->curtime;
	}
	else
		m_flSetpieceCloseStartTime = -1;

	if (gpGlobals->curtime <= m_flStateEnterTime + sv_ball_chargedshotblocktime_corner.GetFloat()
		|| m_flSetpieceCloseStartTime != -1 && gpGlobals->curtime > m_flSetpieceCloseStartTime + sv_ball_setpiece_close_time.GetFloat())
	{
		m_pPl->SetChargedshotBlocked(true);
	}
	else
		m_pPl->SetChargedshotBlocked(false);

	if (!m_pPl->ShotsBlocked()
		&& m_pPl->ShotButtonsReleased()
		&& CanReachBallStandingXY()
		&& (m_pPl->IsNormalshooting() || !m_pPl->ChargedshotBlocked() && m_pPl->IsChargedshooting()))
	{
		//EmitSound("Crowd.Way");
		m_pPl->AddCorner();
		RemoveAllTouches();
		DoGroundShot(false);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_CORNER_Leave(ball_state_t newState)
{
}

void CMatchBall::State_GOAL_Enter()
{
	bool isOwnGoal;
	int scoringTeam;
	CSDKPlayer *pScorer = NULL;
	CSDKPlayer *pFirstAssister = NULL;
	CSDKPlayer *pSecondAssister = NULL;
	GetGoalInfo(isOwnGoal, scoringTeam, &pScorer, &pFirstAssister, &pSecondAssister);

	m_pPl = pScorer;

	float delay = sv_ball_goalcelebduration.GetFloat();

	if (sv_replays.GetBool())
	{
		delay += sv_replay_duration1.GetFloat();

		if (sv_replay_count.GetInt() >= 2)
			delay += sv_replay_duration2.GetFloat();

		if (sv_replay_count.GetInt() >= 3)
			delay += sv_replay_duration3.GetFloat();
	}

	IGameEvent *pEvent = gameeventmanager->CreateEvent("transition");
	if (pEvent)
	{
		pEvent->SetInt("firstdelay", sv_ball_goalcelebduration.GetInt());
		pEvent->SetInt("seconddelay", delay);
		gameeventmanager->FireEvent(pEvent);
	}

	State_Transition(BALL_STATE_KICKOFF, 0, delay);

	ReplayManager()->StartReplay(false);
}

void CMatchBall::State_GOAL_Think()
{
	for (int i = 1; i <= gpGlobals->maxClients; i++)
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		if (pPl->GetTeamNumber() == m_nTeam)
			pPl->AddFlag(FL_ATCONTROLS | FL_USE_TV_CAM);
		else
			pPl->AddFlag(FL_CELEB);
	}
}

void CMatchBall::State_GOAL_Leave(ball_state_t newState)
{
	ReplayManager()->StopReplay();

	for (int i = 1; i <= gpGlobals->maxClients; i++)
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		pPl->RemoveFlag(FL_CELEB | FL_ATCONTROLS | FL_USE_TV_CAM);
		pPl->DoServerAnimationEvent(PLAYERANIMEVENT_CANCEL);
	}
}

void CMatchBall::State_FREEKICK_Enter()
{
	SetPos(m_vFoulPos);
}

void CMatchBall::State_FREEKICK_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, m_nFouledTeam))
	{
		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, m_nFouledTeam))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl && (m_vPos - GetGlobalTeam(m_nFouledTeam)->m_vGoalCenter).Length2D() <= sv_ball_freekickdist_owngoal.GetInt()) // Close to own goal
			m_pPl = GetGlobalTeam(m_nFouledTeam)->GetPlayerByPosType(POS_GK);

		if (!CSDKPlayer::IsOnField(m_pPl) || m_pPl->GetTeamPosType() == POS_GK && m_pPl->IsBot())
			m_pPl = FindNearestPlayer(m_nFouledTeam);

		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_FREEKICK, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x, m_vPos.y - 35 * m_pPl->GetTeam()->m_nForward, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();<commit_msg>Close #391<commit_after>#include "cbase.h"
#include "match_ball.h"
#include "team.h"
#include "ios_replaymanager.h"

extern ConVar
	sv_ball_bodypos_keeperhands,
	sv_ball_chargedshot_minstrength,
	sv_ball_chargedshot_maxstrength,
	sv_ball_keepershot_minangle,
	sv_ball_maxplayerfinddist,
	sv_ball_keeperthrow_strength,
	sv_ball_slidezstart,
	sv_ball_slidezend,
	sv_ball_slidesidereach_ball,
	sv_ball_slideforwardreach_ball,
	sv_ball_slidebackwardreach_ball,
	sv_ball_keeperthrow_minpostdelay;

ConVar
	sv_ball_statetransition_postmessagedelay_short			("sv_ball_statetransition_postmessagedelay_short",			"0.1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_postmessagedelay_normal			("sv_ball_statetransition_postmessagedelay_normal",			"1.25",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_postmessagedelay_long			("sv_ball_statetransition_postmessagedelay_long",			"2.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_messagedelay_normal				("sv_ball_statetransition_messagedelay_normal",				"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_statetransition_messagedelay_short				("sv_ball_statetransition_messagedelay_short",				"0.1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_yellowcardballdist_forward						("sv_ball_yellowcardballdist_forward",						"70",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_yellowcardballdist_backward						("sv_ball_yellowcardballdist_backward",						"70",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalreplay_count								("sv_ball_goalreplay_count",								"2",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalreplay_delay								("sv_ball_goalreplay_delay",								"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_pass_mindist								("sv_ball_stats_pass_mindist",								"300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_clearance_minspeed						("sv_ball_stats_clearance_minspeed",						"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_shot_mindist								("sv_ball_stats_shot_mindist",								"270",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_save_minspeed								("sv_ball_stats_save_minspeed",								"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_stats_assist_maxtime							("sv_ball_stats_assist_maxtime",							"8",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_duration_freekick						("sv_ball_advantage_duration_freekick",						"3",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_ignore_duration_freekick				("sv_ball_advantage_ignore_duration_freekick",				"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_duration_penalty						("sv_ball_advantage_duration_penalty",						"1.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_advantage_ignore_duration_penalty				("sv_ball_advantage_ignore_duration_penalty",				"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_offsidedist										("sv_ball_offsidedist",										"60",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_goalcelebduration								("sv_ball_goalcelebduration",								"8.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_setpiece_close_time								("sv_ball_setpiece_close_time",								"0.75",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_setpiece_close_dist								("sv_ball_setpiece_close_dist",								"75",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_doubletouchfouls								("sv_ball_doubletouchfouls",								"1",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_player_secondyellowcard_banduration				("sv_ball_player_secondyellowcard_banduration",				"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_player_redcard_banduration						("sv_ball_player_redcard_banduration",						"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickdist_owngoal							("sv_ball_freekickdist_owngoal",							"850",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickdist_opponentgoal						("sv_ball_freekickdist_opponentgoal",						"1300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_freekickangle_opponentgoal						("sv_ball_freekickangle_opponentgoal",						"60",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_closetogoaldist									("sv_ball_closetogoaldist",									"1300",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedshotblocktime_freekick					("sv_ball_chargedshotblocktime_freekick",					"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedshotblocktime_corner						("sv_ball_chargedshotblocktime_corner",						"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_shotsblocktime_penalty							("sv_ball_shotsblocktime_penalty",							"4.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slidesidereach_foul								("sv_ball_slidesidereach_foul",								"10",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slideforwardreach_foul							("sv_ball_slideforwardreach_foul",							"25",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_slidebackwardreach_foul							("sv_ball_slidebackwardreach_foul",							"20",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_powerthrow_strength								("sv_ball_powerthrow_strength",								"720",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedthrow_minstrength						("sv_ball_chargedthrow_minstrength",						"450",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_chargedthrow_maxstrength						("sv_ball_chargedthrow_maxstrength",						"990",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_timelimit_setpiece								("sv_ball_timelimit_setpiece",								"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_timelimit_remotecontrolled						("sv_ball_timelimit_remotecontrolled",						"15",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throwin_minangle								("sv_ball_throwin_minangle",								"-5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throwin_minstrength								("sv_ball_throwin_minstrength",								"270",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_foulcheckdelay									("sv_ball_foulcheckdelay",									"2.0",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_foulcheckmaxdist								("sv_ball_foulcheckmaxdist",								"200",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_kickoff_strength								("sv_ball_kickoff_strength",								"350",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_kickoff_minpostdelay							("sv_ball_kickoff_minpostdelay",							"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY),
	sv_ball_throw_minpostdelay								("sv_ball_throw_minpostdelay",								"0.5",		FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY);



LINK_ENTITY_TO_CLASS( match_ball, CMatchBall );

BEGIN_DATADESC(	CMatchBall )
END_DATADESC()

IMPLEMENT_SERVERCLASS_ST( CMatchBall, DT_MatchBall )
	SendPropEHandle(SENDINFO(m_pLastActivePlayer)),
	SendPropInt(SENDINFO(m_nLastActiveTeam)),
END_SEND_TABLE()

CMatchBall *g_pMatchBall = NULL;

CMatchBall *CreateMatchBall(const Vector &pos)
{
	if (!g_pMatchBall)
		g_pMatchBall = static_cast<CMatchBall *>(CreateEntityByName("match_ball"));

	g_pMatchBall->SetAbsOrigin(pos);
	g_pMatchBall->Spawn();
	g_pMatchBall->SetPos(pos);

	return g_pMatchBall;
}

CMatchBall *GetMatchBall()
{
	return g_pMatchBall;
}

CMatchBall::CMatchBall()
{
	m_pLastActivePlayer = NULL;
	m_nLastActiveTeam = TEAM_NONE;
	m_pPossessingPl = NULL;
	m_nPossessingTeam = TEAM_NONE;
	m_flPossessionStart = -1;
	m_ePenaltyState = PENALTY_NONE;
	m_bIsAdvantage = false;
	m_bBallInAirAfterThrowIn = false;
	m_flStateTimelimit = -1;
}

CMatchBall::~CMatchBall()
{
	g_pMatchBall = NULL;
}

void CMatchBall::Spawn()
{
	//TODO: Move the ball skin parsing to a better spot
	CBallInfo::ParseBallSkins();
	
	CBall::Spawn();
}

void CMatchBall::Reset()
{
	CBall::Reset();

	m_pLastActivePlayer = NULL;
	m_pSetpieceTaker = NULL;
	m_flStateLeaveTime = gpGlobals->curtime;
	m_flNextStateMessageTime = -1;
	m_pOtherPl = NULL;
	m_pPossessingPl = NULL;
	m_nPossessingTeam = TEAM_NONE;
	m_flPossessionStart = -1;
	m_ePenaltyState = PENALTY_NONE;
	m_bIsAdvantage = false;
	m_bBallInAirAfterThrowIn = false;
	m_flStateTimelimit = -1;

	UnmarkOffsidePlayers();
	RemoveAllTouches();
}

void CMatchBall::State_Transition(ball_state_t nextState, float nextStateMessageDelay /*= 0*/, float nextStatePostMessageDelay /*= 0*/, bool cancelQueuedState /*= false*/)
{
	if (nextState != BALL_STATE_KEEPERHANDS)
		m_bIsAdvantage = false;

	if (nextState != BALL_STATE_NORMAL)
		m_bBallInAirAfterThrowIn = false;

	if (nextStateMessageDelay == 0 && nextStatePostMessageDelay == 0)
	{
		State_Leave(nextState);
		State_Enter(nextState, cancelQueuedState);
	}
	else
	{
		m_eNextState = nextState;
		m_flNextStateMessageTime = gpGlobals->curtime + nextStateMessageDelay;
		m_flStateLeaveTime = gpGlobals->curtime + nextStateMessageDelay + nextStatePostMessageDelay;
		m_bHasQueuedState = true;

		if (State_Get() != BALL_STATE_GOAL)
			SDKGameRules()->AddBallStateTransitionTime(nextStateMessageDelay + nextStatePostMessageDelay);
	}
}

void CMatchBall::State_Enter(ball_state_t newState, bool cancelQueuedState)
{
	if (cancelQueuedState)
	{
		m_eNextState = BALL_STATE_NONE;
		m_bHasQueuedState = false;
	}

	m_eBallState = newState;
	m_pCurStateInfo = State_LookupInfo( newState );

	m_flStateEnterTime = gpGlobals->curtime;
	m_flStateTimelimit = -1;
	m_flNextStateMessageTime = -1;

	m_pPl = NULL;
	m_pOtherPl = NULL;
	m_pSetpieceTaker = NULL;

	IGameEvent *pEvent = gameeventmanager->CreateEvent("ball_state");
	if (pEvent)
	{
		pEvent->SetInt("state", State_Get());
		gameeventmanager->FireEvent(pEvent);
	}

	// Initialize the new state.
	if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
	{
		(this->*m_pCurStateInfo->pfnEnterState)();
	}

	//State_Think();
}

void CMatchBall::State_Leave(ball_state_t newState)
{
	SDKGameRules()->DisableShield();

	if (CSDKPlayer::IsOnField(m_pPl))
	{
		m_pPl->SetChargedshotBlocked(false);
		m_pPl->SetShotsBlocked(false);
	}

	if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
	{
		(this->*m_pCurStateInfo->pfnLeaveState)(newState);
	}
}

void CMatchBall::State_Think()
{
	m_pPhys->GetPosition(&m_vPos, &m_aAng);
	m_pPhys->GetVelocity(&m_vVel, &m_vRot);

	CheckFieldZone();
	CheckPenBoxPosition();

	if (m_eNextState != BALL_STATE_NONE)
	{
		if (m_flNextStateMessageTime != -1 && gpGlobals->curtime >= m_flNextStateMessageTime && m_eNextState != BALL_STATE_KICKOFF)
		{
			SendNotifications();
			m_flNextStateMessageTime = -1;
		}
		else if (gpGlobals->curtime >= m_flStateLeaveTime)
		{
			State_Leave(m_eNextState);
			State_Enter(m_eNextState, true);
			return;
		}
	}

	if (State_Get() == BALL_STATE_THROWIN || State_Get() == BALL_STATE_CORNER || State_Get() == BALL_STATE_GOALKICK || State_Get() == BALL_STATE_KICKOFF)
	{
		if (SDKGameRules()->CheckTimeout())
			m_flStateTimelimit = -1;
	}

	if (m_pCurStateInfo
		&& State_Get() != BALL_STATE_NORMAL
		&& m_eNextState == BALL_STATE_NONE
		&& CSDKPlayer::IsOnField(m_pPl)
		&& m_flStateTimelimit != -1
		&& gpGlobals->curtime >= m_flStateTimelimit) // Player is afk or timed out
	{
		m_pPl->SetDesiredTeam(TEAM_SPECTATOR, m_pPl->GetTeamNumber(), 0, true, false, false);
	}

	if (m_pCurStateInfo && m_pCurStateInfo->pfnThink)
	{	
		(this->*m_pCurStateInfo->pfnThink)();
	}

	if (m_pPl) // Set info for the client
	{
		m_pLastActivePlayer = m_pPl;
		m_nLastActiveTeam = m_pPl->GetTeamNumber();
	}
}

void CMatchBall::State_STATIC_Enter()
{
	SDKGameRules()->StopMeteringClockStoppedTime();
}

void CMatchBall::State_STATIC_Think()
{
}

void CMatchBall::State_STATIC_Leave(ball_state_t newState)
{
	if (!SDKGameRules()->IsIntermissionState())
		SDKGameRules()->StartMeteringClockStoppedTime();
}

void CMatchBall::State_NORMAL_Enter()
{
	m_pPhys->EnableMotion(true);
	EnablePlayerCollisions(true);
	m_pPhys->Wake();
	SDKGameRules()->StopMeteringClockStoppedTime();
	//SetMatchEvent(MATCH_EVENT_NONE);
	//SetMatchSubEvent(MATCH_EVENT_NONE);
}

void CMatchBall::State_NORMAL_Think()
{
	if (m_eNextState == BALL_STATE_GOAL)
		return;

	if (SDKGameRules()->State_Get() == MATCH_PERIOD_PENALTIES)
	{
		if (m_ePenaltyState == PENALTY_KICKED && !CheckGoal() && !CheckGoalLine())
		{
			m_pPl = GetGlobalTeam(m_nFoulingTeam)->GetPlayerByPosType(POS_GK);

			if (m_pPl && (m_pPl->IsShooting() || m_pPl->IsKeeperDiving()))
			{
				UpdateCarrier();
				DoBodyPartAction();
			}
		}

		return;
	}

	if (!SDKGameRules()->IsIntermissionState() && !m_bHasQueuedState)
	{
		CheckAdvantage();

		if (!CheckOffside())
		{
			if (!CheckGoal())
			{
				if (!CheckGoalLine())
				{
					CheckSideline();
				}
			}
		}
	}

	for (int ignoredPlayerBits = 0;;)
	{
		m_pPl = FindNearestPlayer(TEAM_NONE, FL_POS_ANY, false, ignoredPlayerBits, sv_ball_maxplayerfinddist.GetFloat());

		if (!m_pPl)
			return;

		UpdateCarrier();

		// The current player was able to perform an action, so exit the loop
		if (DoBodyPartAction())
			break;

		// Exclude the current player from subsequent checks
		ignoredPlayerBits |= (1 << (m_pPl->entindex() - 1));

		m_pPl = NULL;
	}
}

void CMatchBall::State_NORMAL_Leave(ball_state_t newState)
{
	UnmarkOffsidePlayers();
	UpdatePossession(NULL);

	if (!SDKGameRules()->IsIntermissionState())
		SDKGameRules()->StartMeteringClockStoppedTime();
}

void CMatchBall::State_THROWIN_Enter()
{
	EnablePlayerCollisions(false);
}

void CMatchBall::State_THROWIN_Think()
{
	Vector groundPos = Vector(m_vTriggerTouchPos.x < SDKGameRules()->m_vKickOff.GetX() ? SDKGameRules()->m_vFieldMin.GetX() - BALL_PHYS_RADIUS - 15 : SDKGameRules()->m_vFieldMax.GetX() + BALL_PHYS_RADIUS + 15, m_vTriggerTouchPos.y, SDKGameRules()->m_vKickOff.GetZ());

	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		SetPos(groundPos);

		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
		{
			SetPos(groundPos + Vector(30 * Sign(SDKGameRules()->m_vKickOff.GetX() - m_vTriggerTouchPos.x), 0, 0));
			return State_Transition(BALL_STATE_NORMAL);
		}

		SDKGameRules()->EnableShield(SHIELD_THROWIN, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(groundPos, true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		SetPos(groundPos + Vector(0, 0, m_pPl->GetPlayerMaxs().z + 2));
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_THROWIN);
		m_pPl->SetShotButtonsReleased(false);
		m_pPl->SetShotsBlocked(false);
	}

	UpdateCarrier();

	if (m_pPl->ShotButtonsReleased() && m_pPl->IsChargedshooting())
	{
		QAngle ang = m_aPlAng;

		ang[PITCH] = min(sv_ball_throwin_minangle.GetFloat(), m_aPlAng[PITCH]);

		Vector dir;
		AngleVectors(ang, &dir);
		float strength = GetChargedshotStrength(GetPitchCoeff(), sv_ball_chargedthrow_minstrength.GetInt(), sv_ball_chargedthrow_maxstrength.GetInt());

		Vector vel = dir * max(strength, sv_ball_throwin_minstrength.GetInt());

		m_pPl->AddThrowIn();
		RemoveAllTouches();
		SetVel(vel, 0, FL_SPIN_FORCE_NONE, BODY_PART_HANDS, false, sv_ball_throw_minpostdelay.GetFloat(), true);
		m_bBallInAirAfterThrowIn = true;
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_THROWIN_Leave(ball_state_t newState)
{
	if (CSDKPlayer::IsOnField(m_pPl))
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_THROW);

	EnablePlayerCollisions(true);
}

void CMatchBall::State_KICKOFF_Enter()
{
	for (int i = 1; i <= gpGlobals->maxClients; i++) 
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		pPl->m_Shared.SetStamina(100);
	}

	SetPos(SDKGameRules()->m_vKickOff);
}

void CMatchBall::State_KICKOFF_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, SDKGameRules()->GetKickOffTeam()))
	{
		m_pPl = NULL;

		m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_ATTACKER | FL_POS_RIGHT);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_MIDFIELDER | FL_POS_RIGHT);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_LEFT);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_CENTER);
		if (!m_pPl)
			m_pPl = FindNearestPlayer(SDKGameRules()->GetKickOffTeam(), FL_POS_DEFENDER | FL_POS_RIGHT);

		if (!m_pPl)
		{
			if (SDKGameRules()->m_nShieldType != SHIELD_KICKOFF)
				SDKGameRules()->EnableShield(SHIELD_KICKOFF, GetGlobalTeam(TEAM_HOME)->GetTeamNumber(), SDKGameRules()->m_vKickOff);

			if (!CSDKPlayer::PlayersAtTargetPos())
				return;

			return State_Transition(BALL_STATE_NORMAL);
		}

		SDKGameRules()->EnableShield(SHIELD_KICKOFF, m_pPl->GetTeamNumber(), SDKGameRules()->m_vKickOff);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x - m_pPl->GetTeam()->m_nRight * 30, m_vPos.y, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);

		EmitSound("Ball.Whistle");

		IGameEvent *pEvent = gameeventmanager->CreateEvent("kickoff");
		if (pEvent)
		{
			pEvent->SetInt("team", m_pPl->GetTeamNumber());
			gameeventmanager->FireEvent(pEvent);
		}
	}

	if (!CSDKPlayer::IsOnField(m_pOtherPl, SDKGameRules()->GetKickOffTeam()) || m_pOtherPl == m_pPl)
	{
		m_pOtherPl = NULL;

		m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_ATTACKER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_MIDFIELDER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_RIGHT, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_CENTER, false, (1 << (m_pPl->entindex() - 1)));
		if (!m_pOtherPl)
			m_pOtherPl = FindNearestPlayer(m_pPl->GetTeamNumber(), FL_POS_DEFENDER | FL_POS_LEFT, false, (1 << (m_pPl->entindex() - 1)));

		if (m_pOtherPl)
		{
			m_pOtherPl->SetPosInsideShield(Vector(m_vPos.x + m_pPl->GetTeam()->m_nRight * 100, m_vPos.y, SDKGameRules()->m_vKickOff.GetZ()), true);
		}
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	for (int i = 1; i <= gpGlobals->maxClients; i++) 
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		if (pPl->GetFlags() & FL_ATCONTROLS)
		{
			if (pPl != m_pPl && pPl != m_pOtherPl)
				pPl->RemoveFlag(FL_ATCONTROLS);
		}
	}

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->SetShotButtonsReleased(false);
		m_pPl->SetShotsBlocked(false);
	}

	UpdateCarrier();

	if (m_pPl->ShotButtonsReleased() && m_pPl->IsShooting())
	{
		RemoveAllTouches();
		SetVel(m_vPlForward2D * sv_ball_kickoff_strength.GetInt(), 0, FL_SPIN_FORCE_NONE, BODY_PART_FEET, false, sv_ball_kickoff_minpostdelay.GetFloat(), true);
		m_pPl->DoServerAnimationEvent(PLAYERANIMEVENT_BLANK);
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		if (m_pOtherPl)
			m_pOtherPl->RemoveFlag(FL_ATCONTROLS);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_KICKOFF_Leave(ball_state_t newState)
{
}

void CMatchBall::State_GOALKICK_Enter()
{
	Vector ballPos;

	CTeam *pTeam = GetGlobalTeam(LastOppTeam(false));

	if (Sign(m_vTriggerTouchPos.x - SDKGameRules()->m_vKickOff.GetX()) == pTeam->m_nRight)
		ballPos = pTeam->m_vGoalkickRight;
	else
		ballPos = pTeam->m_vGoalkickLeft;

	SetPos(ballPos);
}

void CMatchBall::State_GOALKICK_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = GetGlobalTeam(LastOppTeam(false))->GetPlayerByPosType(POS_GK);

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_GOALKICK, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x, m_vPos.y - 100 * m_pPl->GetTeam()->m_nForward, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->SetShotsBlocked(false);
		m_pPl->SetShotButtonsReleased(false);
	}

	if (IsPlayerClose())
	{
		if (m_flSetpieceCloseStartTime == -1)
			m_flSetpieceCloseStartTime = gpGlobals->curtime;
	}
	else
		m_flSetpieceCloseStartTime = -1;

	if (m_flSetpieceCloseStartTime != -1 && gpGlobals->curtime > m_flSetpieceCloseStartTime + sv_ball_setpiece_close_time.GetFloat())
	{
		m_pPl->SetChargedshotBlocked(true);
	}
	else
		m_pPl->SetChargedshotBlocked(false);

	if (!m_pPl->ShotsBlocked()
		&& m_pPl->ShotButtonsReleased()
		&& CanReachBallStandingXY()
		&& (m_pPl->IsNormalshooting() || !m_pPl->ChargedshotBlocked() && m_pPl->IsChargedshooting()))
	{
		m_pPl->AddGoalKick();
		RemoveAllTouches();
		DoGroundShot(false);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_GOALKICK_Leave(ball_state_t newState)
{
}

void CMatchBall::State_CORNER_Enter()
{
	Vector ballPos;
	CTeam *pTeam = GetGlobalTeam(LastTeam(false));

	if (Sign(m_vTriggerTouchPos.x - SDKGameRules()->m_vKickOff.GetX()) == pTeam->m_nRight)
		ballPos = pTeam->m_vCornerRight;
	else
		ballPos = pTeam->m_vCornerLeft;
	
	SetPos(ballPos);
}

void CMatchBall::State_CORNER_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, LastOppTeam(false)))
	{
		m_pPl = NULL;

		if (CSDKPlayer::IsOnField(m_pSetpieceTaker, LastOppTeam(false)))
			m_pPl = m_pSetpieceTaker;

		if (!m_pPl)
			m_pPl = FindNearestPlayer(LastOppTeam(false));

		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_CORNER, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x - 25 * Sign((SDKGameRules()->m_vKickOff - m_vPos).x), m_vPos.y - 25 * Sign((SDKGameRules()->m_vKickOff - m_vPos).y), SDKGameRules()->m_vKickOff[2]), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();
	
	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
		m_pPl->RemoveFlag(FL_ATCONTROLS);
		m_pPl->SetShotsBlocked(false);
		m_pPl->SetShotButtonsReleased(false);
	}

	if (IsPlayerClose())
	{
		if (m_flSetpieceCloseStartTime == -1)
			m_flSetpieceCloseStartTime = gpGlobals->curtime;
	}
	else
		m_flSetpieceCloseStartTime = -1;

	if (gpGlobals->curtime <= m_flStateEnterTime + sv_ball_chargedshotblocktime_corner.GetFloat()
		|| m_flSetpieceCloseStartTime != -1 && gpGlobals->curtime > m_flSetpieceCloseStartTime + sv_ball_setpiece_close_time.GetFloat())
	{
		m_pPl->SetChargedshotBlocked(true);
	}
	else
		m_pPl->SetChargedshotBlocked(false);

	if (!m_pPl->ShotsBlocked()
		&& m_pPl->ShotButtonsReleased()
		&& CanReachBallStandingXY()
		&& (m_pPl->IsNormalshooting() || !m_pPl->ChargedshotBlocked() && m_pPl->IsChargedshooting()))
	{
		//EmitSound("Crowd.Way");
		m_pPl->AddCorner();
		RemoveAllTouches();
		DoGroundShot(false);
		State_Transition(BALL_STATE_NORMAL);
	}
}

void CMatchBall::State_CORNER_Leave(ball_state_t newState)
{
}

void CMatchBall::State_GOAL_Enter()
{
	bool isOwnGoal;
	int scoringTeam;
	CSDKPlayer *pScorer = NULL;
	CSDKPlayer *pFirstAssister = NULL;
	CSDKPlayer *pSecondAssister = NULL;
	GetGoalInfo(isOwnGoal, scoringTeam, &pScorer, &pFirstAssister, &pSecondAssister);

	m_pPl = pScorer;

	float delay = sv_ball_goalcelebduration.GetFloat();

	if (sv_replays.GetBool())
	{
		delay += sv_replay_duration1.GetFloat();

		if (sv_replay_count.GetInt() >= 2)
			delay += sv_replay_duration2.GetFloat();

		if (sv_replay_count.GetInt() >= 3)
			delay += sv_replay_duration3.GetFloat();
	}

	IGameEvent *pEvent = gameeventmanager->CreateEvent("transition");
	if (pEvent)
	{
		pEvent->SetInt("firstdelay", sv_ball_goalcelebduration.GetInt());
		pEvent->SetInt("seconddelay", delay);
		gameeventmanager->FireEvent(pEvent);
	}

	State_Transition(BALL_STATE_KICKOFF, 0, delay);

	ReplayManager()->StartReplay(false);
}

void CMatchBall::State_GOAL_Think()
{
	for (int i = 1; i <= gpGlobals->maxClients; i++)
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		if (pPl->GetTeamNumber() == m_nTeam)
			pPl->AddFlag(FL_ATCONTROLS | FL_USE_TV_CAM);
		else
			pPl->AddFlag(FL_CELEB);
	}
}

void CMatchBall::State_GOAL_Leave(ball_state_t newState)
{
	ReplayManager()->StopReplay();

	for (int i = 1; i <= gpGlobals->maxClients; i++)
	{
		CSDKPlayer *pPl = ToSDKPlayer(UTIL_PlayerByIndex(i));

		if (!CSDKPlayer::IsOnField(pPl))
			continue;

		pPl->RemoveFlag(FL_CELEB | FL_ATCONTROLS | FL_USE_TV_CAM);
		pPl->DoServerAnimationEvent(PLAYERANIMEVENT_CANCEL);
	}
}

void CMatchBall::State_FREEKICK_Enter()
{
	SetPos(m_vFoulPos);
}

void CMatchBall::State_FREEKICK_Think()
{
	if (!CSDKPlayer::IsOnField(m_pPl, m_nFouledTeam))
	{
		// Take player assigned by captain
		m_pPl = m_pSetpieceTaker;

		// Take fouled player if close to opponent goal
		if (!CSDKPlayer::IsOnField(m_pPl, m_nFouledTeam) && (m_vPos - GetGlobalTeam(m_nFoulingTeam)->m_vGoalCenter).Length2D() <= sv_ball_freekickdist_opponentgoal.GetInt())
			m_pPl = m_pFouledPl;

		// Take keeper if close to own goal
		if (!CSDKPlayer::IsOnField(m_pPl, m_nFouledTeam) && (m_vPos - GetGlobalTeam(m_nFouledTeam)->m_vGoalCenter).Length2D() <= sv_ball_freekickdist_owngoal.GetInt())
			m_pPl = GetGlobalTeam(m_nFouledTeam)->GetPlayerByPosType(POS_GK);

		// Take player closest to foul spot if no one else found or found keeper is bot
		if (!CSDKPlayer::IsOnField(m_pPl, m_nFouledTeam) || m_pPl->GetTeamPosType() == POS_GK && m_pPl->IsBot())
			m_pPl = FindNearestPlayer(m_nFouledTeam);

		// Bail out if no player found
		if (!m_pPl)
			return State_Transition(BALL_STATE_NORMAL);

		SDKGameRules()->EnableShield(SHIELD_FREEKICK, m_pPl->GetTeamNumber(), m_vPos);
		m_pPl->SetPosInsideShield(Vector(m_vPos.x, m_vPos.y - 35 * m_pPl->GetTeam()->m_nForward, SDKGameRules()->m_vKickOff.GetZ()), true);
		m_flStateTimelimit = -1;
		m_pPl->SetShotsBlocked(true);
	}

	if (!CSDKPlayer::PlayersAtTargetPos())
		return;

	UpdateCarrier();

	if (m_flStateTimelimit == -1)
	{
		m_flStateTimelimit = gpGlobals->curtime + sv_ball_timelimit_setpiece.GetFloat();
{'fraction_non_alphanumeric': 0.1264285975097674, 'fraction_numerical': 0.007339248548581444, 'mean_word_length': 5.841743692230827, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 430, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6694219', 'n_tokens_mistral': 24953, 'n_tokens_neox': 22317, 'n_words': 2803}