#include ww2x\_wwx_weapons;
#include ww2x\_drm;

init()
{
	precacheString(&"MP_AMERICAN");
	precacheString(&"MP_BRITISH");
	precacheString(&"MP_RUSSIAN");
	
	switch(game["allies"])
	{
	case "american":
		precacheShader("mpflag_american");
		break;
	
	case "british":
		precacheShader("mpflag_british");
		break;
	
	case "russian":
		precacheShader("mpflag_russian");
		break;
	}

	assert(game["axis"] == "german");
	precacheShader("mpflag_german");
	precacheShader("mpflag_spectator");

	if(getcvar("scr_teambalance") == "") setCvar("scr_teambalance", "0");
	level.teambalance = getcvarInt("scr_teambalance");
	level.teambalancetimer = 0;
	
	setPlayerModels();

	if(getcvar("g_gametype") != "dm")
	{
		level thread onPlayerConnect();
		level thread updateTeamBalanceCvar();

		wait .15;
	
		if(getcvar("g_gametype") == "sd" || getcvar("g_gametype") == "lts" || getcvar("g_gametype") == "ihtf" || getcvar("g_gametype") == "lms")
		{
			if(level.teambalance > 0)
			{
		    	if(isDefined(game["BalanceTeamsNextRound"])) iprintlnbold(&"MP_AUTOBALANCE_NEXT_ROUND");
	
				level waittill("restarting");
	
				if(isDefined(game["BalanceTeamsNextRound"]))
				{
					level balanceTeams();
					game["BalanceTeamsNextRound"] = undefined;
				}
				else if(!getTeamBalance()) game["BalanceTeamsNextRound"] = true;
			}
		}
		else
		{
			for(;;)
			{
				if(level.teambalance > 0)
				{
					if(!getTeamBalance())
					{
						iprintlnbold(&"MP_AUTOBALANCE_SECONDS", 15);
					    wait 15;
	
						if(!getTeamBalance()) level balanceTeams();
					}
					
					wait 59;
				}
				
				wait 1;
			}
		}
	}
}

onPlayerConnect()
{
	for(;;)
	{
		level waittill("connecting", player);
		
		player thread onJoinedTeam();
		player thread onJoinedSpectators();
	}
}

onJoinedTeam()
{
	self endon("disconnect");
	
	for(;;)
	{
		self waittill("joined_team");
		self updateTeamTime();
	}
}

onJoinedSpectators()
{
	self endon("disconnect");
	
	for(;;)
	{
		self waittill("joined_spectators");
		self.pers["teamTime"] = undefined;
	}
}

updateTeamTime()
{
	if(getcvar("g_gametype") == "sd") self.pers["teamTime"] = game["timepassed"] + ((getTime() - level.starttime) / 1000) / 60.0;
	else self.pers["teamTime"] = (gettime() / 1000);
}

updateTeamBalanceCvar()
{
	for(;;)
	{
		teambalance = getcvarInt("scr_teambalance");
		if(level.teambalance != teambalance)
			level.teambalance = getcvarInt("scr_teambalance");

		wait 1;
	}
}

getTeamBalance()
{
	level.team["allies"] = 0;
	level.team["axis"] = 0;

	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
	{
		if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) level.team["allies"]++;
		else if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) level.team["axis"]++;
	}
	
	if((level.team["allies"] > (level.team["axis"] + level.teambalance)) || (level.team["axis"] > (level.team["allies"] + level.teambalance))) return false;
	else return true;
}

balanceTeams()
{
	iprintlnbold(&"MP_AUTOBALANCE_NOW");
	//Create/Clear the team arrays
	AlliedPlayers = [];
	AxisPlayers = [];
	
	// Populate the team arrays
	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
	{
		if(isPlayer(players[i]) && !isDefined(players[i].pers["teamTime"])) continue;

		if(isPlayer(players[i]))
		{			
			if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) AlliedPlayers[AlliedPlayers.size] = players[i];
			else if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) AxisPlayers[AxisPlayers.size] = players[i];
		}
	}
	
	MostRecent = undefined;
	
	while((AlliedPlayers.size > (AxisPlayers.size + 1)) || (AxisPlayers.size > (AlliedPlayers.size + 1)))
	{	
		if(AlliedPlayers.size > (AxisPlayers.size + 1))
		{
			// Move the player that's been on the team the shortest ammount of time (highest teamTime value)
			for(j = 0; j < AlliedPlayers.size; j++)
			{
				if(isPlayer(AlliedPlayers[j]) && (isDefined(AlliedPlayers[j].dont_auto_balance) || !isDefined(AlliedPlayers[j].pers) || !isDefined(AlliedPlayers[j].pers["teamTime"]))) continue;

				if(isPlayer(AlliedPlayers[j]))
				{				
					if(!isDefined(MostRecent)) MostRecent = AlliedPlayers[j];
					else if(isPlayer(AlliedPlayers[j]) && isDefined(AlliedPlayers[j].pers["teamTime"]) && AlliedPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"]) MostRecent = AlliedPlayers[j];
				}
			}

			if(isDefined(MostRecent))
			{			
				if(getcvar("g_gametype") == "sd" || getcvar("g_gametype") == "lts" || getcvar("g_gametype") == "ihtf" || getcvar("g_gametype") == "lms") MostRecent changeTeam_RoundBased("axis");
				else MostRecent changeTeam("axis");
			}
		}
		else if(AxisPlayers.size > (AlliedPlayers.size + 1))
		{
			// Move the player that's been on the team the shortest ammount of time (highest teamTime value)
			for(j = 0; j < AxisPlayers.size; j++)
			{
				if(isPlayer(AxisPlayers[j]) && (isDefined(AxisPlayers[j].dont_auto_balance) || !isDefined(AxisPlayers[j].pers) || !isDefined(AxisPlayers[j].pers["teamTime"]))) continue;

				if(isPlayer(AxisPlayers[j]))
				{
					if(!isDefined(MostRecent)) MostRecent = AxisPlayers[j];
					else if(isPlayer(AxisPlayers[j]) && isDefined(AxisPlayers[j].pers["teamTime"]) && AxisPlayers[j].pers["teamTime"] > MostRecent.pers["teamTime"]) MostRecent = AxisPlayers[j];
				}
			}

			if(isDefined(MostRecent))
			{
				if(getcvar("g_gametype") == "sd" || getcvar("g_gametype") == "lts" || getcvar("g_gametype") == "ihtf" || getcvar("g_gametype") == "lms") MostRecent changeTeam_RoundBased("allies");
				else MostRecent changeTeam("allies");
			}
		}

		MostRecent = undefined;
		AlliedPlayers = [];
		AxisPlayers = [];
		
		players = getentarray("player", "classname");
		for(i = 0; i < players.size; i++)
		{
			if(isPlayer(players[i]))
			{
				if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) AlliedPlayers[AlliedPlayers.size] = players[i];
				else if((isDefined(players[i].pers["team"])) &&(players[i].pers["team"] == "axis")) AxisPlayers[AxisPlayers.size] = players[i];
			}
		}
	}
}

changeTeam(team)
{
	if(self.sessionstate != "dead")
	{
		// Set a flag on the player to they aren't robbed points for dying - the callback will remove the flag
		self.switching_teams = true;
		self.joining_team = team;
		self.leaving_team = self.pers["team"];
		
		// Suicide the player so they can't hit escape and fail the team balance
		self suicide();
	}

	self.pers["team"] = team;
	self.pers["savedmodel"] = undefined;
	self.sessionteam = self.pers["team"];

	// create the WW2X weapon array
	self ww2x\_wwx_weapons::setWeaponArray();

	// clear game weapon arrarys
	self ww2x\_wwx_clientcontrol::clearWeapons();
	
	// update spectator permissions immediately on change of team
	self maps\mp\gametypes\_spectating::setSpectatePermissions();

	// allow weapon change, do not allow team change!
	self setClientCvar("ui_allow_weaponchange", "1");
	self setClientCvar("ui_allow_teamchange", 0);
	
	if(self.pers["team"] == "allies")
	{
		self setClientCvar("g_scriptMainMenu", game["menu_weapon_allies"]);
		self openMenu(game["menu_weapon_allies"]);
	}
	else
	{
		self setClientCvar("g_scriptMainMenu", game["menu_weapon_axis"]);
		self openMenu(game["menu_weapon_axis"]);
	}
	
	self updateTeamTime();
	
	self notify("end_respawn");
}

changeTeam_RoundBased(team)
{
	self.pers["team"] = team;
	self.pers["savedmodel"] = undefined;

	// create the WW2X weapon array
	self ww2x\_wwx_weapons::setWeaponArray();

	// clear game weapon arrarys
	self ww2x\_wwx_clientcontrol::clearWeapons();

	// do not allow team change!
	self setClientCvar("ui_allow_teamchange", 0);

	// reset the flag for secondary weapon system
	self.pers["first_time"] = true;
	
	self updateTeamTime();
}

setPlayerModels()
{

	// Workaround for the 127 bones error with mobile turrets
	if ( drm_getcvarint ("scr_allow_mg30cal") || drm_getcvarint ("scr_allow_mg42") || drm_getcvarint ("scr_allow_dmg42") || drm_getcvarint ("scr_allow_dmg30cal"))
	{
		if (isdefined (game["russian_soldiertype"]) && (game["russian_soldiertype"] == "coats"))
			game["russian_soldiertype"] = "padded";
		if (isdefined (game["german_soldiertype"]) && (game["german_soldiertype"] == "winterdark"))
			game["german_soldiertype"] = "winterlight";
	}

	switch(game["allies"])
	{
		case "british":
			if(isDefined(game["british_soldiertype"]) && game["british_soldiertype"] == "africa")
			{
				mptype\british_africa::precache();
				game["allies_model"] = mptype\british_africa::main;
			}
			else
			{
				mptype\british_normandy::precache();
				game["allies_model"] = mptype\british_normandy::main;
			}
			break;
	
		case "russian":
			if(isDefined(game["russian_soldiertype"]) && game["russian_soldiertype"] == "padded")
			{
				mptype\russian_padded::precache();
				game["allies_model"] = mptype\russian_padded::main;
			}
			else
			{
				mptype\russian_coat::precache();
				game["allies_model"] = mptype\russian_coat::main;
			}
			break;
	
		case "american":
		default:
			mptype\american_normandy::precache();
			game["allies_model"] = mptype\american_normandy::main;
	}
	
	if(isDefined(game["german_soldiertype"]) && game["german_soldiertype"] == "winterdark")
	{
		mptype\german_winterdark::precache();
		game["axis_model"] = mptype\german_winterdark::main;
	}
	else if(isDefined(game["german_soldiertype"]) && game["german_soldiertype"] == "winterlight")
	{
		mptype\german_winterlight::precache();
		game["axis_model"] = mptype\german_winterlight::main;
	}
	else if(isDefined(game["german_soldiertype"]) && game["german_soldiertype"] == "africa")
	{
		mptype\german_africa::precache();
		game["axis_model"] = mptype\german_africa::main;
	}
	else
	{
		mptype\german_normandy::precache();
		game["axis_model"] = mptype\german_normandy::main;	
	}
}

model()
{
	self detachAll();
	
	if(self.pers["team"] == "allies") [[game["allies_model"] ]]();
	else if(self.pers["team"] == "axis") [[game["axis_model"] ]]();

	self.pers["savedmodel"] = maps\mp\_utility::saveModel();
}

CountPlayers()
{
	//chad
	players = getentarray("player", "classname");
	allies = 0;
	axis = 0;
	for(i = 0; i < players.size; i++)
	{
		if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "allies")) allies++;
		else if((isDefined(players[i].pers["team"])) && (players[i].pers["team"] == "axis")) axis++;
	}
	players["allies"] = allies;
	players["axis"] = axis;
	return players;
}

addTestClients()
{
	// don't add bots if using the game start delay system
	if(level.wwx_gtsdelay && isDefined(game["gtsdone"])) return;

	level waittill("gobots");

	createBotWeaponsArray();

	if(level.wwx_diag_bots)
	{
		logprint("*********************************\n");
		logprint("* Bot weapons - BOT debug *\n");
		logprint("*********************************\n");
		
		for(i = 0; i < level.wwx_botweapons_allies.size; i++)
			logprint("Allied bot weapon [" + i + "] = " + level.wwx_botweapons_allies[i] + " \n");

		logprint("\n");

		for(i = 0; i < level.wwx_botweapons_axis.size; i++)
			logprint("Axis bot weapon [" + i + "] = " + level.wwx_botweapons_axis[i] + " \n");

		logprint("********************************\n");
		logprint("* BOT Weapon debug end  *\n");
		logprint("********************************\n");

		logprint("\n");
	}

	testclients = getcvarInt("scr_testclients");

	for(i = 0; i < testclients; i++)
	{
		ent[i] = addtestclient();

		if(i & 1) team = "axis";
		else team = "allies";
		
		ent[i] thread testClient(team);
	}
}

testClient(team)
{
	self endon("wwx_spawned");

	// wait here while the teams are configured
	while(!isDefined(self.pers["team"]) || !isDefined(game["allies"]) || !isDefined(game["axis"])) wait .05;

	// choose a team
	self notify("menuresponse", game["menu_team"], team);
	wait 0.5;

	// flag the bot
	self.pers["isbot"] = true;

	// set the weapon variable
	weapon = undefined;

	// keep looping here until all the weapons have been selected
	for(;;)
	{
		wait 0.05;

		if(self.pers["team"] == "allies") weapon = level.wwx_botweapons_allies[randomInt(level.wwx_botweapons_allies.size)];
		else weapon = level.wwx_botweapons_axis[randomInt(level.wwx_botweapons_axis.size)];

		// check for weapon class only
		if(level.wwx_wepo_class)
		{
			switch(level.wwx_wepo_class)
			{
				case 1:	classname = "pistol";		break;	// pistol only
				case 2:	classname = "sniper";		break;	// sniper only
				case 3:	classname = "mg";			break;	// mg only
				case 4:	classname = "smg";			break;	// smg only
				case 5:	classname = "rifle";			break;	// rifle only
				case 6: classname = "boltrifle";	break;	// bolt action rifle only
				case 7: classname = "knife";	break;	// knives only

				default: classname = "shotgun";	break;	// shotgun only
			}

			// if the weapon is not part of this class, shouldn't happen, but just in case!
			if(!isWeaponType(weapon, classname)) continue;
		}

		// check that the bot hasn't tried to select a pistol when secondary weapon system is running, or when weapon class (not pistols only)
		if(isWeaponType(weapon, "pistol") && (level.wwx_wepo_secondary || level.wwx_wepo_class >= 2)) continue;

		// if the weapon limiter is on, and this weapon is not allowrd, get another one!
		if(!level.wwx_wepo_class && level.wwx_wepo_limiter && level.weapons[weapon].limit == 0) continue;

		// choose a primary weapon
		if(!isDefined(self.pers["weapon"]) || !isDefined(self.pers["weapon1"]))
			self notify("menuresponse", game["menu_weapon_" + self.pers["team"]], weapon);

		// log the weapon if in diagnostic mode
		if(level.wwx_diag_bots) logprint(self.name + " chose team " + self.pers["team"] + " and primary weapon " + weapon + "\n");

		// choose a secondary weapon if secondary system is on
		if(level.wwx_wepo_secondary)
		{
			wait 0.05;

			// wait till they have selected a primary before choosing a secondary
			if((isDefined(self.pers["weapon"]) || isDefined(self.pers["weapon1"])) && !isDefined(self.pers["weapon2"]))
			{
				if(weapon != self.pers["weapon"] && weapon != self.pers["weapon1"])
					self notify("menuresponse", game["menu_weapon_" + self.pers["team"] +"_sec"], weapon);

				// log the weapon if in diagnostic mode
				if(level.wwx_diag_bots) logprint(self.name + " chose team " + self.pers["team"] + " and secondary weapon " + weapon + "\n");			
			}
		}
	}
}

createBotWeaponsArray()
{
	classname = undefined;
	allweapons = false;

	switch(level.wwx_wepo_class)
	{
		case 1:	classname = "pistol";		break;	// pistol only
		case 2:	classname = "sniper";		break;	// sniper only
		case 3:	classname = "mg";			break;	// mg only
		case 4:	classname = "smg";			break;	// smg only
		case 5:	classname = "rifle";			break;	// rifle only
		case 6: classname = "boltrifle";	break;	// bolt action rifle only
		case 7: classname = "knife";	break;	// knives only
		case 8: classname = "shotgun";	break;	// shotgun only

		default:	allweapons = true;			break;	// all weapons
	}

	level.wwx_botweapons_allies = [];
	level.wwx_botweapons_axis = [];

	// build the botweapon arrays
	for(i = 0; i < level.weaponnames.size; i++)
	{
		weaponname = level.weaponnames[i];

		if(weaponname != "fraggrenade" && weaponname != "smokegrenade")
		{
			if(allweapons)	// all weapons for game allies and game axis
			{
				 if(level.wwx_wepo_secondary && level.wwx_wepo_sec_pistols || !level.wwx_wepo_class) // if using secondary system with pistols or all weapons available (team)
				 {
				 	if(isWeaponType(weaponname, game["allies"])) level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 	if(isWeaponType(weaponname, game["axis"])) level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				}
				else if(level.wwx_wepo_secondary && !level.wwx_wepo_sec_pistols) // if using secondary system without pistols
				{
				 	if(!isWeaponType(weaponname, "pistol"))
				 	{
					 	if(isWeaponType(weaponname, game["allies"])) level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 		if(isWeaponType(weaponname, game["axis"])) level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				 	}
				}
			}
			else // must be weapon based (secondary system disabled)
			{
				if(level.wwx_wepo_team_only) // team based, only add weapons of this type that match the game allies and the game axis
				{
					if(isWeaponType(weaponname, classname))
					{
				 		if(isWeaponType(weaponname, game["allies"])) level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 		if(isWeaponType(weaponname, game["axis"])) level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				 	}
				}
				else // not team based so add all weapons of this type
				{
					if(isWeaponType(weaponname, classname))
					{
				 		level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 		level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				 	}
				}
	
				if(level.wwx_wepo_sidearm && isWeaponType(weaponname, "pistol")) // if sidearm (pistol) is allowed add it
				{
					if(level.wwx_wepo_team_only) // only add pistols that match the game allies and the game axis
					{
						if(isWeaponType(weaponname, classname))
						{
				 			if(isWeaponType(weaponname, game["allies"])) level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 			if(isWeaponType(weaponname, game["axis"])) level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				 		}
					}
					else // not team based so add all pistols
					{
				 		level.wwx_botweapons_allies[level.wwx_botweapons_allies.size] = weaponname;
				 		level.wwx_botweapons_axis[level.wwx_botweapons_axis.size] = weaponname;
				 	}
				}
			}
		}
	}
}