/*
	Capture the Flag Back - WW2X mod compatible version
	Author : La Truffe
	
	Credits : Matthias (original CTFB in Admiral mod), Wizard220, Marc, Astoroth (WW2X mod), Ravir (cvardef function)

	Version : 1.1

	Objective: 	Score points for your team by capturing the enemy's flag and returning it to your base
	Map ends:	When one team reaches the score limit, or time limit is reached
	Respawning:	Instant / At base

	Level requirements
	------------------
		Spawnpoints:
			classname		mp_ctf_spawn_allied
			Allied players spawn from these.
			classname		mp_ctf_spawn_axis
			Axis players spawn from these.
			classname		mp_dm_spawn
			Flags spawn from these in random position mode.

		Spectator Spawnpoints:
			classname		mp_global_intermission
			Spectators spawn from these and intermission is viewed from these positions.
			Atleast one is required, any more and they are randomly chosen between.

	Level script requirements
	-------------------------
		Team Definitions:
			game["allies"] = "american";
			game["axis"] = "german";
			This sets the nationalities of the teams. Allies can be american, british, or russian. Axis can be german.

		If using minefields or exploders:
			maps\mp\_load::main();

	Optional level script settings
	------------------------------
		Soldier Type and Variation:
			game["american_soldiertype"] = "normandy";
			game["german_soldiertype"] = "normandy";
			This sets what character models are used for each nationality on a particular map.

			Valid settings:
				american_soldiertype	normandy
				british_soldiertype		normandy, africa
				russian_soldiertype		coats, padded
				german_soldiertype		normandy, africa, winterlight, winterdark
*/
#include ww2x\_drm;

main()
{
	level.callbackStartGameType = ::Callback_StartGameType;
	level.callbackPlayerConnect = ::Callback_PlayerConnect;
	level.callbackPlayerDisconnect = ::Callback_PlayerDisconnect;
	level.callbackPlayerDamage = ::Callback_PlayerDamage;
	level.callbackPlayerKilled = ::Callback_PlayerKilled;
	maps\mp\gametypes\_callbacksetup::SetupCallbacks();

	level.autoassign = ww2x\_wwx_clientcontrol::menuAutoAssign;
	level.allies = ww2x\_wwx_clientcontrol::menuAllies;
	level.axis = ww2x\_wwx_clientcontrol::menuAxis;
	level.spectator = ww2x\_wwx_clientcontrol::menuSpectator;
	level.weapon = ww2x\_wwx_clientcontrol::menuWeapon;
	level.spawnplayer = ::spawnplayer;

	level.endgameconfirmed = ::endMap;

	ww2x\_wwx_varcache::main();

}

Callback_StartGameType()
{
	level.splitscreen = isSplitScreen();

	// defaults if not defined in level script
	if(!isDefined(game["allies"]))
		game["allies"] = "american";
	if(!isDefined(game["axis"]))
		game["axis"] = "german";

	// server cvar overrides
	if(drm_getCvar("scr_allies") != "")
		game["allies"] = drm_getCvar("scr_allies");
	if(drm_getCvar("scr_axis") != "")
		game["axis"] = drm_getCvar("scr_axis");

	level.compassflag_allies = "compass_flag_" + game["allies"];
	level.compassflag_axis = "compass_flag_" + game["axis"];
	level.objpointflag_allies = "objpoint_flagpatch1_" + game["allies"];
	level.objpointflag_axis = "objpoint_flagpatch1_" + game["axis"];
	level.objpointflagmissing_allies = "objpoint_flagmissing_" + game["allies"];
	level.objpointflagmissing_axis = "objpoint_flagmissing_" + game["axis"];
	level.hudflag_allies = "compass_flag_" + game["allies"];
	level.hudflag_axis = "compass_flag_" + game["axis"];
	
	level.hudflagflash_allies = "hud_flagflash_" + game["allies"];
	level.hudflagflash_axis = "hud_flagflash_" + game["axis"];

	if (! isDefined (game["precachedone"]))
	{
		if(!level.wwx_ranksystem)
		{
			precacheStatusIcon("hud_status_connecting");
	            precacheStatusIcon("hud_status_dead");
	            precacheStatusIcon(level.hudflag_allies);
	            precacheStatusIcon(level.hudflag_axis);

		}
	precacheRumble("damage_heavy");
	precacheShader(level.compassflag_allies);
	precacheShader(level.compassflag_axis);
	precacheShader(level.objpointflag_allies);
	precacheShader(level.objpointflag_axis);
	precacheShader(level.hudflag_allies);
	precacheShader(level.hudflag_axis);
	precacheShader(level.hudflagflash_allies);
	precacheShader(level.hudflagflash_axis);
	precacheShader(level.objpointflag_allies);
	precacheShader(level.objpointflag_axis);
	precacheShader(level.objpointflagmissing_allies);
	precacheShader(level.objpointflagmissing_axis);
	precacheModel("xmodel/prop_flag_" + game["allies"]);
	precacheModel("xmodel/prop_flag_" + game["axis"]);
	precacheModel("xmodel/prop_flag_" + game["allies"] + "_carry");
	precacheModel("xmodel/prop_flag_" + game["axis"] + "_carry");
	precacheString(&"MP_TIME_TILL_SPAWN");
	precacheString (&"MP_CTFB_OBJ_TEXT");
	precacheString (&"MP_CTFB_OBJ_TEXT_NOSCORE");
	precacheString (&"MP_CTFB_ENEMY_FLAG_CAPTURED");
	precacheString (&"MP_CTFB_YOUR_FLAG_WAS_CAPTURED");
	precacheString (&"MP_CTFB_YOUR_FLAG_WAS_RETURNED");
	precacheString (&"MP_CTFB_YOUR_FLAG_WAS_TAKEN");
	precacheString (&"MP_CTFB_ENEMY_FLAG_TAKEN");
	precacheString (&"MP_CTFB_YOUR_FLAG_WAS_PICKED_UP");
	precacheString (&"MP_CTFB_DEFEND");
	precacheString (&"MP_CTFB_ASSIST");
	precacheString (&"MP_CTFB_AUTO_RETURN");
	precacheString(&"PLATFORM_PRESS_TO_SPAWN");

		game["precachedone"] = true;
	}

	thread maps\mp\gametypes\_menus::init();
	thread maps\mp\gametypes\_serversettings::init();
	thread maps\mp\gametypes\_clientids::init();
	thread maps\mp\gametypes\_teams::init();
	thread maps\mp\gametypes\_weapons::init();
	thread maps\mp\gametypes\_scoreboard::init();
	thread maps\mp\gametypes\_killcam::init();
	thread maps\mp\gametypes\_shellshock::init();
	thread maps\mp\gametypes\_hud_teamscore::init();
	thread maps\mp\gametypes\_deathicons::init();
	thread maps\mp\gametypes\_damagefeedback::init();
	thread maps\mp\gametypes\_healthoverlay::init();
	thread maps\mp\gametypes\_friendicons::init();
	thread maps\mp\gametypes\_spectating::init();
	thread maps\mp\gametypes\_grenadeindicators::init();
	thread maps\mp\gametypes\_landmines::init();

	level.xenon = (drm_getcvar("xenonGame") == "true");
	if(level.xenon) // Xenon only
		thread maps\mp\gametypes\_richpresence::init();
	else // PC only
		thread maps\mp\gametypes\_quickmessages::init();

	thread ww2x\_wwx_varcache::postmapload();
	thread ww2x\_wwx_tempvote::init();

	setClientNameMode("auto_change");

	/*// Time limit per map
	if(drm_getCvar("scr_ctfb_timelimit") == "")
		setCvar("scr_ctfb_timelimit", "30");
	else if(drm_getCvarFloat("scr_ctfb_timelimit") > 1440)
		setCvar("scr_ctfb_timelimit", "1440");
	level.timelimit = drm_getCvarFloat("scr_ctfb_timelimit");
	setCvar("ui_ctfb_timelimit", level.timelimit);
	makeCvarServerInfo("ui_ctfb_timelimit", "30");

	// Score limit per map
	if(drm_getCvar("scr_ctfb_scorelimit") == "")
		setCvar("scr_ctfb_scorelimit", "5");
	level.scorelimit = drm_getCvarInt("scr_ctfb_scorelimit");
	setCvar("ui_ctfb_scorelimit", level.scorelimit);
	makeCvarServerInfo("ui_ctfb_scorelimit", "5");*/

	// Force respawning
	if(drm_getCvar("scr_forcerespawn") == "")
		setCvar("scr_forcerespawn", "0");

	level.random_flag_position = [[level.drm_cvardef]] ("scr_ctfb_random_flag_position", 0, 0, 1, "int");
	level.show_enemy_own_flag = [[level.drm_cvardef]] ("scr_ctfb_show_enemy_own_flag", 1, 0, 1, "int");
	level.show_enemy_own_flag_after_sec = [[level.drm_cvardef]] ("scr_ctfb_show_enemy_own_flag_after_sec", 60, 20, 900, "int");
	level.show_enemy_own_flag_time = [[level.drm_cvardef]] ("scr_ctfb_show_enemy_own_flag_time", 60, 20, 900, "int");
	level.points_capture_flag = [[level.drm_cvardef]] ("scr_ctfb_points_capture_flag", 10, 1, 50, "int");
	level.points_returned_flag = [[level.drm_cvardef]] ("scr_ctfb_points_returned_flag", 2, 1, 50, "int");
	level.points_defend = [[level.drm_cvardef]] ("scr_ctfb_points_defend", 2, 1, 50, "int");
	level.points_assist = [[level.drm_cvardef]] ("scr_ctfb_points_assist", 3, 1, 50, "int");
	level.flagprotectiondistance = [[level.drm_cvardef]] ("scr_ctfb_flagprotectiondistance", 800, 1, 999999, "int");
	level.respawndelay = [[level.drm_cvardef]] ("scr_ctfb_respawn_delay", 10, 0, 600, "int");
	level.flagautoreturndelay = [[level.drm_cvardef]] ("scr_ctfb_flagautoreturndelay", 120, 0, 99999, "int");
	level.objective_icon = [[level.drm_cvardef]] ("scr_objectiveicon", 1, 0, 1, "int");
	setCvar ("ui_gtinfo_d", level.respawndelay);
	makeCvarServerInfo ("ui_gtinfo_d", "10");

	spawnpointname = "mp_ctf_spawn_allied";
	spawnpoints = getentarray(spawnpointname, "classname");

	if(!spawnpoints.size)
	{
		maps\mp\gametypes\_callbacksetup::AbortLevel();
		return;
	}

	for(i = 0; i < spawnpoints.size; i++)
		spawnpoints[i] placeSpawnpoint();

	spawnpointname = "mp_ctf_spawn_axis";
	spawnpoints = getentarray(spawnpointname, "classname");

	if(!spawnpoints.size)
	{
		maps\mp\gametypes\_callbacksetup::AbortLevel();
		return;
	}

	for(i = 0; i < spawnpoints.size; i++)
		spawnpoints[i] PlaceSpawnpoint();

	if (level.random_flag_position)
	{
		spawnpointname = "mp_dm_spawn";
		spawnpoints = getentarray (spawnpointname, "classname");

		if (! spawnpoints.size)
		{
			maps\mp\gametypes\_callbacksetup::AbortLevel();
			return;
		}

		for (i = 0; i < spawnpoints.size; i++)
			spawnpoints[i] placeSpawnpoint();	
	}

	allowed[0] = "ctf";
	maps\mp\gametypes\_gameobjects::main(allowed);

	if(!isDefined(game["state"]))
		game["state"] = "playing";

	level.mapended = false;

	level.team["allies"] = 0;
	level.team["axis"] = 0;

	minefields = [];
	minefields = getentarray("minefield", "targetname");
	trigger_hurts = [];
	trigger_hurts = getentarray("trigger_hurt", "classname");

	level.flag_returners = minefields;
	for(i = 0; i < trigger_hurts.size; i++)
		level.flag_returners[level.flag_returners.size] = trigger_hurts[i];

	if (level.wwx_gtsdelay)
	{
		if (isDefined (game["gtsdone"]) && game["gtsdone"])
			thread initFlags();
	}
	else
		thread initFlags();

	thread startGame();
	//thread updateGametypeCvars();
	thread maps\mp\gametypes\_teams::addTestClients();
	thread maps\mp\gametypes\_redirect::redirect_init();

	ww2x\_wwx_main::main();
}

dummy()
{
	waittillframeend;

	if(isdefined(self))
		level notify("connecting", self);
}

Callback_PlayerConnect()
{
	thread dummy();

	thread ww2x\_wwx_clientcontrol::wwxplayerconnect();
      self ww2x\_wwx_tempvote::voteMenuChk();

	if(!level.wwx_ranksystem) self.statusicon = "hud_status_connecting";
	self waittill("begin");
	self.statusicon = "";

	level notify("connected", self);

	thread ww2x\_wwx_clientcontrol::wwxplayerjoinedserver();

	lpselfnum = self getEntityNumber();
	lpGuid = self getGuid();
	logPrint("J;" + lpGuid + ";" + lpselfnum + ";" + self.name + "\n");

	if(game["state"] == "intermission")
	{

		ww2x\_wwx_spawn::spawnIntermission();

		return;
	}

	level endon("intermission");

	if(level.splitscreen)
		scriptMainMenu = game["menu_ingame_spectator"];
	else
		scriptMainMenu = game["menu_ingame"];

	if(isDefined(self.pers["team"]) && self.pers["team"] != "spectator")
	{
		self setClientCvar("ui_allow_weaponchange", "1");

		if(self.pers["team"] == "allies")
			self.sessionteam = "allies";
		else
			self.sessionteam = "axis";

		self maps\mp\gametypes\_spectating::setSpectatePermissions();

		if(isDefined(self.pers["weapon"]))
			spawnPlayer();
		else
		{

			ww2x\_wwx_spawn::spawnspectator();

			if(self.pers["team"] == "allies")
			{
				self openMenu(game["menu_weapon_allies"]);
				scriptMainMenu = game["menu_weapon_allies"];
			}
			else
			{
				self openMenu(game["menu_weapon_axis"]);
				scriptMainMenu = game["menu_weapon_axis"];
			}
		}
	}
	else
	{
		self setClientCvar("ui_allow_weaponchange", "0");

		if(!level.xenon)
		{
			if(!isdefined(self.pers["skipserverinfo"]))
				self openMenu(game["menu_serverinfo"]);
		}
		else
			self openMenu(game["menu_team"]);

		self.pers["team"] = "spectator";
		self.sessionteam = "spectator";

		ww2x\_wwx_spawn::spawnspectator();
	}

	self setClientCvar("g_scriptMainMenu", scriptMainMenu);
}

Callback_PlayerDisconnect()
{
	self dropFlag();
	self dropOwnFlag();

	self ww2x\_wwx_clientcontrol::wwxplayerdisconnect();

	if(isdefined(self.pers["team"]))
	{
		if(self.pers["team"] == "allies")
			setplayerteamrank(self, 0, 0);
		else if(self.pers["team"] == "axis")
			setplayerteamrank(self, 1, 0);
		else if(self.pers["team"] == "spectator")
			setplayerteamrank(self, 2, 0);
	}

	lpselfnum = self getEntityNumber();
	lpGuid = self getGuid();
	logPrint("Q;" + lpGuid + ";" + lpselfnum + ";" + self.name + "\n");
}

Callback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime)
{
	if(self.sessionteam == "spectator" || self.wwx_invulnerable) return;

	if(isDefined(sWeapon) && sWeapon == "smoke_grenade_american_fire_mp" || sWeapon == "smoke_grenade_russian_fire_mp" || sWeapon == "smoke_grenade_british_fire_mp" || sWeapon == "smoke_grenade_german_fire_mp" || sWeapon == "smoke_grenade_american_gas_mp" || sWeapon == "smoke_grenade_russian_gas_mp" || sWeapon == "smoke_grenade_british_gas_mp" || sWeapon == "smoke_grenade_german_gas_mp" || sWeapon == "fire_mp" || sWeapon == "gas_mp")
	{
	 if((sWeapon == "smoke_grenade_american_fire_mp" || sWeapon == "smoke_grenade_russian_fire_mp" || sWeapon == "smoke_grenade_british_fire_mp" || sWeapon == "smoke_grenade_german_fire_mp" || sWeapon == "fire_mp") && sMeansOfDeath != "MOD_MELEE")
		{
			if (!isDefined(vPoint))
				vPoint = self.origin + (0,0,11);

			if(isDefined(level.cocktail) && level.cocktail == vPoint)
				return;
			level.cocktail = vPoint;
			level thread ww2x\_wwx_firenades::MonitorCocktail(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, level.cocktail, vDir, sHitLoc, psOffsetTime);
			return;

		}
		else if((sWeapon == "smoke_grenade_american_gas_mp" || sWeapon == "smoke_grenade_russian_gas_mp" || sWeapon == "smoke_grenade_british_gas_mp" || sWeapon == "smoke_grenade_german_gas_mp" || sWeapon == "gas_mp") && sMeansOfDeath != "MOD_MELEE")
		{
			if (!isDefined(vPoint))
				vPoint = self.origin + (0,0,11);
			if(isDefined(level.mustardgas) && level.mustardgas == vPoint)
				return;
			level.mustardgas = vPoint;
			level thread ww2x\_wwx_firenades::MonitorMustardGas(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, level.mustardgas, vDir, sHitLoc, psOffsetTime);
			return;
		}
	}

	// Don't do knockback if the damage direction was not specified
	if(!isDefined(vDir))
		iDFlags |= level.iDFLAGS_NO_KNOCKBACK;

	friendly = undefined;

	// check for completely getting out of the damage
	if(!(iDFlags & level.iDFLAGS_NO_PROTECTION))
	{
		if(isPlayer(eAttacker) && (self != eAttacker) && (self.pers["team"] == eAttacker.pers["team"]))
		{
			if(level.friendlyfire == "0")
			{
				return;
			}
			else if(level.friendlyfire == "1")
			{
				// Make sure at least one point of damage is done
				if(iDamage < 1)
					iDamage = 1;

				self finishPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime);

				// Shellshock/Rumble
				self thread maps\mp\gametypes\_shellshock::shellshockOnDamage(sMeansOfDeath, iDamage);
				self playrumble("damage_heavy");
			}
			else if(level.friendlyfire == "2")
			{
				eAttacker.friendlydamage = true;

				iDamage = int(iDamage * .5);

				// Make sure at least one point of damage is done
				if(iDamage < 1)
					iDamage = 1;

				eAttacker finishPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime);
				eAttacker.friendlydamage = undefined;

				friendly = true;
			}
			else if(level.friendlyfire == "3")
			{
				eAttacker.friendlydamage = true;

				iDamage = int(iDamage * .5);

				// Make sure at least one point of damage is done
				if(iDamage < 1)
					iDamage = 1;

				self finishPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime);
				eAttacker finishPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime);
				eAttacker.friendlydamage = undefined;

				friendly = true;

				// Shellshock/Rumble
				self thread maps\mp\gametypes\_shellshock::shellshockOnDamage(sMeansOfDeath, iDamage);
				self playrumble("damage_heavy");
			}
		}
		else
		{
			// Make sure at least one point of damage is done
			if(iDamage < 1)
				iDamage = 1;

			self finishPlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime);

			// Shellshock/Rumble
			self thread maps\mp\gametypes\_shellshock::shellshockOnDamage(sMeansOfDeath, iDamage);
			self playrumble("damage_heavy");
		}

		if(isdefined(eAttacker) && eAttacker != self)
			eAttacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback();
	}

	// Do debug print if it's enabled
	if(drm_getCvarInt("g_debugDamage"))
	{
		println("client:" + self getEntityNumber() + " health:" + self.health +
			" damage:" + iDamage + " hitLoc:" + sHitLoc);
	}

	if(self.sessionstate != "dead")
	{
		lpselfnum = self getEntityNumber();
		lpselfname = self.name;
		lpselfteam = self.pers["team"];
		lpselfGuid = self getGuid();
		lpattackerteam = "";

		if(isPlayer(eAttacker))
		{
			lpattacknum = eAttacker getEntityNumber();
			lpattackGuid = eAttacker getGuid();
			lpattackname = eAttacker.name;
			lpattackerteam = eAttacker.pers["team"];
		}
		else
		{
			lpattacknum = -1;
			lpattackGuid = "";
			lpattackname = "";
			lpattackerteam = "world";
		}

		if(isDefined(friendly))
		{
			lpattacknum = lpselfnum;
			lpattackname = lpselfname;
			lpattackGuid = lpselfGuid;
		}

		logPrint("D;" + lpselfGuid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackGuid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n");
	}
}

Callback_PlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration)
{
	self endon("spawned");
	self notify("killed_player");

	if(self.sessionteam == "spectator")
		return;

	self thread ww2x\_wwx_main::wwxplayerkilled (eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc);

	// If the player was killed by a head shot, let players know it was a head shot kill
	if(sHitLoc == "head" && sMeansOfDeath != "MOD_MELEE")
		sMeansOfDeath = "MOD_HEAD_SHOT";

	// send out an obituary message to all clients about the kill

	self thread ww2x\_wwx_obituary::main (eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc);

	self maps\mp\gametypes\_weapons::dropWeapon();
	self maps\mp\gametypes\_weapons::dropOffhand();
  
	self dropFlag();
	self dropOwnFlag();

	self.sessionstate = "dead";
	if(!level.wwx_ranksystem) self.statusicon = "hud_status_dead";
	self.dead_origin = self.origin;
	self.dead_angles = self.angles;

	if(!isdefined(self.switching_teams))
		self.deaths++;

	lpselfnum = self getEntityNumber();
	lpselfname = self.name;
	lpselfguid = self getGuid();
	lpselfteam = self.pers["team"];
	lpattackerteam = "";

	attackerNum = -1;
	if(isPlayer(attacker))
	{
		if(attacker == self) // killed himself
		{
			doKillcam = false;

			// switching teams
			if(isdefined(self.switching_teams))
			{
				if((self.leaving_team == "allies" && self.joining_team == "axis") || (self.leaving_team == "axis" && self.joining_team == "allies"))
				{
					players = maps\mp\gametypes\_teams::CountPlayers();
					players[self.leaving_team]--;
					players[self.joining_team]++;

					if((players[self.joining_team] - players[self.leaving_team]) > 1)
						attacker.score--;
				}
			}

			if(isdefined(attacker.friendlydamage))
				attacker iprintln(&"MP_FRIENDLY_FIRE_WILL_NOT");
		}
		else
		{
			attackerNum = attacker getEntityNumber();
			doKillcam = true;

			if(self.pers["team"] == attacker.pers["team"]) // killed by a friendly
				attacker.score--;
			else
			{
				attacker.score++;
				attacker CheckProtectedOwnFlag (self.origin);
			}
		}

		lpattacknum = attacker getEntityNumber();
		lpattackguid = attacker getGuid();
		lpattackname = attacker.name;
		lpattackerteam = attacker.pers["team"];
	}
	else // If you weren't killed by a player, you were in the wrong place at the wrong time
	{
		doKillcam = false;

		self.score--;

		lpattacknum = -1;
		lpattackname = "";
		lpattackguid = "";
		lpattackerteam = "world";
	}

	logPrint("K;" + lpselfguid + ";" + lpselfnum + ";" + lpselfteam + ";" + lpselfname + ";" + lpattackguid + ";" + lpattacknum + ";" + lpattackerteam + ";" + lpattackname + ";" + sWeapon + ";" + iDamage + ";" + sMeansOfDeath + ";" + sHitLoc + "\n");

	// Stop thread if map ended on this death
	if(level.mapended)
		return;

	if (isdefined (self.switching_teams))
		self.wwx_team_changed = true;

	self.switching_teams = undefined;
	self.joining_team = undefined;
	self.leaving_team = undefined;

	body = self cloneplayer(deathAnimDuration);
	thread maps\mp\gametypes\_deathicons::addDeathicon(body, self.clientid, self.pers["team"], 5);

	delay = 2;	// Delay the player becoming a spectator till after he's done dying
	self thread respawn_timer(delay);

	wait delay;	// ?? Also required for Callback_PlayerKilled to complete before respawn/killcam can execute

	if(doKillcam && level.killcam)
		self maps\mp\gametypes\_killcam::killcam(attackerNum, delay, psOffsetTime);

	self thread respawn();
}

spawnPlayer()
{
	self endon("disconnect");
	self notify("spawned");
	self notify("end_respawn");

	resettimeout();

	// Stop shellshock and rumble
	self stopShellshock();
	self stoprumble("damage_heavy");

	self.sessionteam = self.pers["team"];
	self.sessionstate = "playing";
	self.spectatorclient = -1;
	self.archivetime = 0;
	self.psoffsettime = 0;
	self.friendlydamage = undefined;
	self.statusicon = "";
	self.maxhealth = 100;
	self.health = self.maxhealth;
	self.dead_origin = undefined;
	self.dead_angles = undefined;

	self ww2x\_wwx_main::wwxprespawn();

	if(self.pers["team"] == "allies")
		spawnpointname = "mp_ctf_spawn_allied";
	else
		spawnpointname = "mp_ctf_spawn_axis";

	if (level.random_flag_position)
		spawnpointname = "mp_dm_spawn";

	spawnpoints = getentarray(spawnpointname, "classname");
	spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_NearTeam(spawnpoints);

	if(isDefined(spawnpoint))
		self spawn(spawnpoint.origin, spawnpoint.angles);
	else
		maps\mp\_utility::error("NO " + spawnpointname + " SPAWNPOINTS IN MAP");

	if(!isDefined(self.pers["savedmodel"]))
		maps\mp\gametypes\_teams::model();
	else
		maps\mp\_utility::loadModel(self.pers["savedmodel"]);

	ww2x\_wwx_weapons::loadout();

	if(!level.splitscreen)
	{
		if(level.scorelimit > 0)
			self setClientCvar("cg_objectiveText", &"MP_CTFB_OBJ_TEXT", level.scorelimit);
		else
			self setClientCvar("cg_objectiveText", &"MP_CTFB_OBJ_TEXT_NOSCORE");
	}
	else
		self setClientCvar("cg_objectiveText", &"MP_CTFB_OBJ_TEXT_NOSCORE");

	self thread updateTimer();

	waittillframeend;

	self ww2x\_wwx_main::wwxpostspawn();

	self notify("spawned_player");
}

respawn()
{
	self endon("disconnect");
	self endon("end_respawn");

	if(!isDefined(self.pers["weapon"]))
		return;

	self.sessionteam = self.pers["team"];
	self.sessionstate = "spectator";

	if(isdefined(self.dead_origin) && isdefined(self.dead_angles))
	{
		origin = self.dead_origin + (0, 0, 16);
		angles = self.dead_angles;
	}
	else
	{
		origin = self.origin + (0, 0, 16);
		angles = self.angles;
	}

	self spawn(origin, angles);

	while(isdefined(self.WaitingToSpawn))
		wait .05;

	if(drm_getCvarInt("scr_forcerespawn") <= 0)
	{
		self thread waitRespawnButton();
		self waittill("respawn");
	}

	self thread spawnPlayer();
}

waitRespawnButton()
{
	self endon("disconnect");
	self endon("end_respawn");
	self endon("respawn");

	wait 0; // Required or the "respawn" notify could happen before it's waittill has begun

	if(!isdefined(self.respawntext))
	{
		self.respawntext = newClientHudElem(self);
		self.respawntext.horzAlign = "center_safearea";
		self.respawntext.vertAlign = "center_safearea";
		self.respawntext.alignX = "center";
		self.respawntext.alignY = "middle";
		self.respawntext.x = 0;
		self.respawntext.y = -50;
		self.respawntext.archived = false;
		self.respawntext.font = "default";
		self.respawntext.fontscale = 2;
		self.respawntext setText(&"PLATFORM_PRESS_TO_SPAWN");
	}

	thread removeRespawnText();
	thread waitRemoveRespawnText("end_respawn");
	thread waitRemoveRespawnText("respawn");

	while(self useButtonPressed() != true)
		wait .05;

	self notify("remove_respawntext");

	self notify("respawn");
}

removeRespawnText()
{
	self waittill("remove_respawntext");

	if(isDefined(self.respawntext))
		self.respawntext destroy();
}

waitRemoveRespawnText(message)
{
	self endon("remove_respawntext");

	self waittill(message);
	self notify("remove_respawntext");
}

startGame()
{
	level.starttime = getTime();

	if(level.timelimit > 0)
	{

		ww2x\_wwx_gtcommon::createClock();

		level.clock setTimer(level.timelimit * 60);
	}

	for(;;)
	{
		checkTimeLimit();
		wait 1;
	}
}

endMap()
{
	game["state"] = "intermission";
	level notify("intermission");

	alliedscore = getTeamScore("allies");
	axisscore = getTeamScore("axis");

	if(alliedscore == axisscore)
	{
		winningteam = "tie";
		losingteam = "tie";
		text = &"MP_THE_GAME_IS_A_TIE";
	}
	else if(alliedscore > axisscore)
	{
		winningteam = "allies";
		losingteam = "axis";
		text = &"MP_ALLIES_WIN";
	}
	else
	{
		winningteam = "axis";
		losingteam = "allies";
		text = &"MP_AXIS_WIN";
	}

	winners = "";
	losers = "";

	if(winningteam == "allies")
		level thread playSoundOnPlayers("MP_announcer_allies_win");
	else if(winningteam == "axis")
		level thread playSoundOnPlayers("MP_announcer_axis_win");
	else
		level thread playSoundOnPlayers("MP_announcer_round_draw");

	ww2x\_wwx_main::wwxendmap();

	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
	{
		player = players[i];

		if((winningteam == "allies") || (winningteam == "axis"))
		{
			lpGuid = player getGuid();
			if((isDefined(player.pers["team"])) && (player.pers["team"] == winningteam))
				winners = (winners + ";" + lpGuid + ";" + player.name);
			else if((isDefined(player.pers["team"])) && (player.pers["team"] == losingteam))
				losers = (losers + ";" + lpGuid + ";" + player.name);
		}

		player closeMenu();
		player closeInGameMenu();
		player setClientCvar("cg_objectiveText", text);

		player ww2x\_wwx_spawn::spawnIntermission();

		if(level.wwx_ranksystem)
		{
			statusicon = player thread ww2x\_wwx_ranksystem::get_Current_Rank();
			if(isdefined(player.statusicon))					
			player.statusicon = statusicon;
		}
	}

	if((winningteam == "allies") || (winningteam == "axis"))
	{
		logPrint("W;" + winningteam + winners + "\n");
		logPrint("L;" + losingteam + losers + "\n");
	}

	// set everyone's rank on xenon
	if(level.xenon)
	{
		players = getentarray("player", "classname");
		highscore = undefined;

		for(i = 0; i < players.size; i++)
		{
			player = players[i];

			if(!isdefined(player.score))
				continue;

			if(!isdefined(highscore) || player.score > highscore)
				highscore = player.score;
		}

		for(i = 0; i < players.size; i++)
		{
			player = players[i];

			if(!isdefined(player.score))
				continue;

			if(highscore <= 0)
				rank = 0;
			else
			{
				rank = int(player.score * 10 / highscore);
				if(rank < 0)
					rank = 0;
			}

			if(player.pers["team"] == "allies")
				setplayerteamrank(player, 0, rank);
			else if(player.pers["team"] == "axis")
				setplayerteamrank(player, 1, rank);
			else if(player.pers["team"] == "spectator")
				setplayerteamrank(player, 2, rank);
		}
		sendranks();
	}

	if (isdefined (level.wwx_endmusic) && level.wwx_endmusic)
		level waittill ("end_music_over");
	else

	wait 15;
	exitLevel(false);
}

checkTimeLimit()
{
	if(level.timelimit <= 0)
		return;

	timepassed = (getTime() - level.starttime) / 1000;
	timepassed = timepassed / 60.0;

	if(timepassed < level.timelimit)
		return;

	if(level.mapended)
		return;
	level.mapended = true;

	if(!level.splitscreen)
		iprintln(&"MP_TIME_LIMIT_REACHED");

	level thread endMap();
}

checkScoreLimit()
{
	if(level.scorelimit <= 0)
		return;

	if(getTeamScore("allies") < level.scorelimit && getTeamScore("axis") < level.scorelimit)
		return;

	if(level.mapended)
		return;
	level.mapended = true;

	if(!level.splitscreen)
		iprintln(&"MP_SCORE_LIMIT_REACHED");

	level thread endMap();
}

/*updateGametypeCvars()
{
	for(;;)
	{
		timelimit = drm_getCvarFloat("scr_ctfb_timelimit");
		if(level.timelimit != timelimit)
		{
			if(timelimit > 1440)
			{
				timelimit = 1440;
				setCvar("scr_ctfb_timelimit", "1440");
			}

			level.timelimit = timelimit;
			setCvar("ui_ctfb_timelimit", level.timelimit);
			level.starttime = getTime();

			if(level.timelimit > 0)
			{
				if(!isDefined(level.clock))

				ww2x\_wwx_gtcommon::createClock();

				level.clock setTimer(level.timelimit * 60);
			}
			else
			{
				if(isDefined(level.clock))
					level.clock destroy();
			}

			checkTimeLimit();
		}

		scorelimit = drm_getCvarInt("scr_ctfb_scorelimit");
		if(level.scorelimit != scorelimit)
		{
			level.scorelimit = scorelimit;
			setCvar("ui_ctfb_scorelimit", level.scorelimit);
			level notify("update_allhud_score");
		}
		checkScoreLimit();

		wait 1;
	}
}*/

initFlags()
{
	maperrors = [];

	allied_flags = getentarray("allied_flag", "targetname");
	if(allied_flags.size < 1)
		maperrors[maperrors.size] = "^1No entities found with \"targetname\" \"allied_flag\"";
	else if(allied_flags.size > 1)
		maperrors[maperrors.size] = "^1More than 1 entity found with \"targetname\" \"allied_flag\"";

	axis_flags = getentarray("axis_flag", "targetname");
	if(axis_flags.size < 1)
		maperrors[maperrors.size] = "^1No entities found with \"targetname\" \"axis_flag\"";
	else if(axis_flags.size > 1)
		maperrors[maperrors.size] = "^1More than 1 entity found with \"targetname\" \"axis_flag\"";

	if(maperrors.size)
	{
		println("^1------------ Map Errors ------------");
		for(i = 0; i < maperrors.size; i++)
			println(maperrors[i]);
		println("^1------------------------------------");

		return;
	}

	allied_flag = getent ("allied_flag", "targetname");
	axis_flag = getent ("axis_flag", "targetname");

	if (level.random_flag_position)
	{
		spawnpoints = getentarray ("mp_dm_spawn", "classname");
		
		allied_flag.origin = (0,0,0);
		axis_flag.origin = (0,0,0);
		
		trys = 0;
		while ((distance (allied_flag.origin, axis_flag.origin) < 2200) || (allied_flag.origin == axis_flag.origin))
		{
			j = randomInt (spawnpoints.size);
			allied_flag.origin = spawnpoints[j].origin;

			j = randomInt (spawnpoints.size);
			axis_flag.origin = spawnpoints[j].origin;
	
			trys ++;

			if (trys > 50)
				break;
		}
	}
	
	if ((distance (axis_flag.origin, allied_flag.origin) < 2000) || (allied_flag.origin == axis_flag.origin))
	{
		allied_flag = getent ("allied_flag", "targetname");
		axis_flag = getent ("axis_flag", "targetname");
	}

	allied_flag.home_origin = allied_flag.origin;
	allied_flag.home_angles = allied_flag.angles;
	allied_flag.flagmodel = spawn("script_model", allied_flag.home_origin);
	allied_flag.flagmodel.angles = allied_flag.home_angles;
	allied_flag.flagmodel setmodel("xmodel/prop_flag_" + game["allies"]);
	allied_flag.basemodel = spawn("script_model", allied_flag.home_origin);
	allied_flag.basemodel.angles = allied_flag.home_angles;
	allied_flag.basemodel setmodel("xmodel/prop_flag_base");
	allied_flag.team = "allies";
	allied_flag.atbase = true;
	allied_flag.objective = 0;
	allied_flag.compassflag = level.compassflag_allies;
	allied_flag.objpointflag = level.objpointflag_allies;
	allied_flag.objpointflagmissing = level.objpointflagmissing_allies;

	allied_flag thread flag();

	axis_flag.home_origin = axis_flag.origin;
	axis_flag.home_angles = axis_flag.angles;
	axis_flag.flagmodel = spawn("script_model", axis_flag.home_origin);
	axis_flag.flagmodel.angles = axis_flag.home_angles;
	axis_flag.flagmodel setmodel("xmodel/prop_flag_" + game["axis"]);
	axis_flag.basemodel = spawn("script_model", axis_flag.home_origin);
	axis_flag.basemodel.angles = axis_flag.home_angles;
	axis_flag.basemodel setmodel("xmodel/prop_flag_base");
	axis_flag.team = "axis";
	axis_flag.atbase = true;
	axis_flag.objective = 1;
	axis_flag.compassflag = level.compassflag_axis;
	axis_flag.objpointflag = level.objpointflag_axis;
	axis_flag.objpointflagmissing = level.objpointflagmissing_axis;

	axis_flag thread flag();

	level.flags	= [];
	level.flags["allies"] = allied_flag;
	level.flags["axis"] = axis_flag;
}

flag()
{
	objective_add(self.objective, "current", self.origin, self.compassflag);
	self createFlagWaypoint();

	for(;;)
	{
		if (level.random_flag_position)
		{
			other = undefined;
			other = self checkFlag();
		}
		else
		{
			self waittill ("trigger", other);
		}

		if(isPlayer(other) && isAlive(other) && (other.pers["team"] != "spectator"))
		{
			if(other.pers["team"] == self.team) // Touched by team
			{
				if(self.atbase)
				{
					if (isdefined (other.flag) && (other.pers["team"] != other.flag.team)) // Captured flag
					{
						println("CAPTURED THE FLAG!");

						friendlyAlias = "ctf_touchcapture";
						enemyAlias = "ctf_enemy_touchcapture";

						if(self.team == "axis")
							enemy = "allies";
						else
							enemy = "axis";

						thread playSoundOnPlayers(friendlyAlias, self.team);
						if(!level.splitscreen)
							thread playSoundOnPlayers(enemyAlias, enemy);

						thread printOnTeamFIXED (&"MP_CTFB_ENEMY_FLAG_CAPTURED", self.team, other);
						thread printOnTeamFIXED (&"MP_CTFB_YOUR_FLAG_WAS_CAPTURED", enemy, other);

						other.flag returnFlag();
						other detachFlag(other.flag);
						other.flag = undefined;
						other.statusicon = "";

						other.score += level.points_capture_flag;

						if (level.wwx_ranksystem)
							other.pers["special"] += level.points_capture_flag;

						teamscore = getTeamScore(other.pers["team"]);
						teamscore += 1;
						setTeamScore(other.pers["team"], teamscore);

						lpselfnum = other getEntityNumber();
						lpselfguid = other getGuid();
						logPrint ("A;" + lpselfguid + ";" + lpselfnum + ";" + other.name + ";" + "ctfb_capture" + "\n");

						level notify("update_teamscore_hud");
						level notify("update_allhud_score");

						checkScoreLimit();
					}
				}
				else // Picked up own flag
				{
					println("PICKED UP OWN FLAG!");
					thread playSoundOnPlayers("ctf_touchown", self.team);
					thread printOnTeamFIXED (&"MP_CTFB_YOUR_FLAG_WAS_PICKED_UP", self.team, other);

					other pickupOwnFlag (self);
					other thread checkBaseHomeOwnFlag (self);

					lpselfnum = other getEntityNumber();
					lpselfguid = other getGuid();
					logPrint ("A;" + lpselfguid + ";" + lpselfnum + ";" + other.name + ";" + "ctfb_pickup_own" + "\n");
				}
			}
			else if(other.pers["team"] != self.team) // Touched by enemy
			{
				println("PICKED UP THE FLAG!");

				friendlyAlias = "ctf_touchenemy";
				enemyAlias = "ctf_enemy_touchenemy";

				if(self.team == "axis")
					enemy = "allies";
				else
					enemy = "axis";

				thread playSoundOnPlayers(friendlyAlias, self.team);
				if(!level.splitscreen)
					thread playSoundOnPlayers(enemyAlias, enemy);

				thread printOnTeamFIXED (&"MP_CTFB_YOUR_FLAG_WAS_TAKEN", self.team, other);
				thread printOnTeamFIXED (&"MP_CTFB_ENEMY_FLAG_TAKEN", enemy, other);

				other pickupFlag(self); // Stolen flag

				lpselfnum = other getEntityNumber();
				lpselfguid = other getGuid();
				logPrint ("A;" + lpselfguid + ";" + lpselfnum + ";" + other.name + ";" + "ctfb_pickup" + "\n");
			}
		}
		wait 0.05;
	}
}

checkFlag()
{
	self notify("checkFlag");
	self endon("checkFlag");

	other = undefined;

	while(isDefined(self) && !isDefined(other))
	{
		wait 0.2;

		players = getentarray("player", "classname");

		for(i = 0; i < players.size; i++)
		{
			if(isDefined(self) && players[i].sessionstate == "playing" && distance(self.origin,players[i].origin) < 65)
				return players[i];				
		}		
	}	
}

checkBaseHomeOwnFlag (flag)
{
	self endon ("disconnect");
	self endon ("killed_player");
	
	self notify ("checkBase");
	self endon ("checkBase");

	while (isDefined (flag))
	{
		wait 0.3;

	
		if (isDefined (flag) && (self.sessionstate == "playing") && (distance (flag.basemodel.origin, self.origin) < 50))
		{
			// Returned flag

			println ("RETURNED THE FLAG!");
			thread playSoundOnPlayers ("ctf_touchown", flag.team);
			thread printOnTeamFIXED (&"MP_CTFB_YOUR_FLAG_WAS_RETURNED", flag.team, self);

			flag returnFlag();
			self detachOwnFlag (flag);
			self.ownflag = undefined; 
			self.statusicon = "";			
			
			self.score += level.points_returned_flag;

			if (level.wwx_ranksystem)
				self.pers["special"] += level.points_returned_flag;

			lpselfnum = self getEntityNumber();
			lpselfguid = self getGuid();
			logPrint ("A;" + lpselfguid + ";" + lpselfnum + ";" + self.name + ";" + "ctfb_return" + "\n");

			level notify ("update_teamscore_hud");
			level notify ("update_allhud_score");
			
			break;
		}
	}	
}

pickupFlag(flag)
{
	self endon ("disconnect");

	flag notify("end_autoreturn");

	flag.origin = flag.origin + (0, 0, -10000);
	flag.flagmodel hide();
	self.flag = flag;

	flag.carrier = self;

	if (! isdefined (self.ownflag))
	{
            if(self.pers["team"] == "allies" && !level.wwx_ranksystem)
		self.statusicon = level.hudflag_axis;
	      else if(self.pers["team"] == "axis" && !level.wwx_ranksystem)
		self.statusicon = level.hudflag_allies;
       }
       else
		self thread BlinkFlags();

	self.dont_auto_balance = true;

	flag deleteFlagWaypoint();
	flag createFlagMissingWaypoint();

	objective_onEntity (flag.objective, self);
	objective_team (flag.objective, self.pers["team"]);

	self attachFlag();

	self thread showFlag_afterTime (flag);
}

pickupOwnFlag(flag)
{
	self endon ("disconnect");

	flag notify("end_autoreturn");

	flag.origin = flag.origin + (0, 0, -10000);
	flag.flagmodel hide();
	self.ownflag = flag;
	
	flag.carrier = self;

	if (! isdefined (self.flag))
	{
            if(self.pers["team"] == "allies" && !level.wwx_ranksystem)
		self.statusicon = level.hudflag_axis;
	      else if(self.pers["team"] == "axis" && !level.wwx_ranksystem)
		self.statusicon = level.hudflag_allies;
	}
            else
		self thread BlinkFlags();

	self.dont_auto_balance = true;

	flag deleteFlagWaypoint();

	//flag createFlagMissingWaypoint();

	objective_onEntity (flag.objective, self);
	objective_team (flag.objective, self.pers["team"]);

	self attachOwnFlag();
	
	self thread showFlag_afterTime (flag);
}

dropFlag()
{
	if(isdefined(self.flag))
	{
		start = self.origin + (0, 0, 10);
		end = start + (0, 0, -2000);
		trace = bulletTrace(start, end, false, undefined);

		self.flag.origin = trace["position"] + (randomint (20), randomint (20), 0);
		self.flag.flagmodel.origin = self.flag.origin;
		self.flag.flagmodel show();
		self.flag.atbase = false;

		self.flag.carrier = undefined;

		objective_position(self.flag.objective, self.flag.origin);
		objective_team(self.flag.objective, "none");

		self.flag createFlagWaypoint();

		self.flag thread autoReturn();
		self detachFlag(self.flag);

		//check if it's in a flag_returner
		for(i = 0; i < level.flag_returners.size; i++)
		{
			if(self.flag.flagmodel istouching(level.flag_returners[i]))
			{
				self.flag returnFlag();
				break;
			}
		}

		self.flag = undefined;
		self.dont_auto_balance = undefined;
	}
}

dropOwnFlag()
{
	if(isdefined(self.ownflag))
	{
		start = self.origin + (0, 0, 10);
		end = start + (0, 0, -2000);
		trace = bulletTrace(start, end, false, undefined);

		self.ownflag.origin = trace["position"] + (randomint(20),randomint(20),0);
		self.ownflag.flagmodel.origin = self.ownflag.origin;
		self.ownflag.flagmodel show();
		self.ownflag.atbase = false;

		self.ownflag.carrier = undefined;

		objective_position(self.ownflag.objective, self.ownflag.origin);
		objective_team(self.ownflag.objective, "none");

		self.ownflag createFlagWaypoint();

		self.ownflag thread autoReturn();
		self detachOwnFlag(self.ownflag);

		//check if it's in a flag_returner
		for(i = 0; i < level.flag_returners.size; i++)
		{
			if(self.ownflag.flagmodel istouching(level.flag_returners[i]))
			{
				self.ownflag returnFlag();
				break;
			}
		}

		self.ownflag = undefined;
		self.dont_auto_balance = undefined;
	}
}

showFlag_afterTime (flag)
{
	if (! level.show_enemy_own_flag)
		return;

	self endon ("disconnect");
	self endon ("killed_player");
	
	flag endon ("end_autoreturn");

	flag_after_sec = level.show_enemy_own_flag_after_sec;
	flag_time = level.show_enemy_own_flag_time;
	
	for ( ; ; )
	{
		wait flag_after_sec;
	
		objective_onEntity (flag.objective, self);
		objective_team (flag.objective, "none");
		
		wait flag_time;
		
		objective_onEntity (flag.objective, self);
		objective_team (flag.objective, self.pers["team"]);	
	}
}

returnFlag()
{
	self notify("end_autoreturn");

 	self.origin = self.home_origin;
 	self.flagmodel.origin = self.home_origin;
 	self.flagmodel.angles = self.home_angles;
	self.flagmodel show();
	self.atbase = true;

	self.carrier = undefined;

	objective_position(self.objective, self.origin);
	objective_team(self.objective, "none");

	self createFlagWaypoint();
	self deleteFlagMissingWaypoint();
}

autoReturn()
{
	self endon("end_autoreturn");

	wait level.flagautoreturndelay;
	
	if (self.team == "allies")
		iprintln (&"MP_CTFB_AUTO_RETURN", &"MP_UPTEAM");
	else
		iprintln (&"MP_CTFB_AUTO_RETURN", &"MP_DOWNTEAM");
	
	self thread returnFlag();
}

attachFlag()
{
	self endon ("disconnect");

	if(isdefined(self.enemyflagAttached))
		return;

	if(self.pers["team"] == "allies")
		flagModel = "xmodel/prop_flag_" + game["axis"] + "_carry";
	else
		flagModel = "xmodel/prop_flag_" + game["allies"] + "_carry";
	
	self attach(flagModel, "J_Spine4", true);
	self.enemyflagAttached = true;
	self.flagAttached = true;
	
	self thread createHudIcon();
}

attachOwnFlag()
{
	self endon ("disconnect");

	if (isdefined (self.ownflagAttached))
		return;

	if (self.pers["team"] == "axis")
		flagModel = "xmodel/prop_flag_" + game["axis"] + "_carry";
	else
		flagModel = "xmodel/prop_flag_" + game["allies"] + "_carry";
	
	self attach( flagModel, "J_Spine2", true);
	self.ownflagAttached = true;
	self.flagAttached = true;
	
	self thread createOwnHudIconOwn();
}

detachFlag(flag)
{
	self endon ("disconnect");

	if(!isdefined(self.enemyflagAttached))
		return;

	if(flag.team == "allies")
		flagModel = "xmodel/prop_flag_" + game["allies"] + "_carry";
	else
		flagModel = "xmodel/prop_flag_" + game["axis"] + "_carry";
		
	self detach(flagModel, "J_Spine4");
	self.enemyflagAttached = undefined;

	if (! isdefined (self.ownflagAttached))
		self.flagAttached = undefined;
	
	self thread deleteHudIcon();
}

detachOwnFlag (flag)
{
	self endon ("disconnect");

	if (!isdefined (self.ownflagAttached))
		return;

	if (self.pers["team"] == "axis")
		flagModel = "xmodel/prop_flag_" + game["axis"] + "_carry";
	else
		flagModel = "xmodel/prop_flag_" + game["allies"] + "_carry";
		
	self detach (flagModel, "J_Spine2");
	self.ownflagAttached = undefined;

	if (! isdefined (self.enemyflagAttached))
		self.flagAttached = undefined;

	self thread deleteOwnHudIcon();
}

createHudIcon()
{
	iconSize = 40;

	self.hud_flag = newClientHudElem(self);
	self.hud_flag.x = 30;
	self.hud_flag.y = 95;
	self.hud_flag.alignX = "center";
	self.hud_flag.alignY = "middle";
	self.hud_flag.horzAlign = "left";
	self.hud_flag.vertAlign = "top";
	self.hud_flag.alpha = 0;

	self.hud_flagflash = newClientHudElem(self);
	self.hud_flagflash.x = 30;
	self.hud_flagflash.y = 95;
	self.hud_flagflash.alignX = "center";
	self.hud_flagflash.alignY = "middle";
	self.hud_flagflash.horzAlign = "left";
	self.hud_flagflash.vertAlign = "top";
	self.hud_flagflash.alpha = 0;
	self.hud_flagflash.sort = 1;

	if(self.pers["team"] == "allies")
	{
		self.hud_flag setShader(level.hudflag_axis, iconSize, iconSize);
		self.hud_flagflash setShader(level.hudflagflash_axis, iconSize, iconSize);
	}
	else
	{
		assert(self.pers["team"] == "axis");
		self.hud_flag setShader(level.hudflag_allies, iconSize, iconSize);
		self.hud_flagflash setShader(level.hudflagflash_allies, iconSize, iconSize);
	}

	self.hud_flagflash fadeOverTime(.2);
	self.hud_flagflash.alpha = 1;

	self.hud_flag fadeOverTime(.2);
	self.hud_flag.alpha = 1;

	wait .2;
	
	if(isdefined(self.hud_flagflash))
	{
		self.hud_flagflash fadeOverTime(1);
		self.hud_flagflash.alpha = 0;
	}
}

createHudIconOwn()
{
	iconSize = 40;

	self.hud_flag = newClientHudElem(self);
	self.hud_flag.x = 30;
	self.hud_flag.y = 95;
	self.hud_flag.alignX = "center";
	self.hud_flag.alignY = "middle";
	self.hud_flag.horzAlign = "left";
	self.hud_flag.vertAlign = "top";
	self.hud_flag.alpha = 0;

	self.hud_flagflash = newClientHudElem(self);
	self.hud_flagflash.x = 30;
	self.hud_flagflash.y = 95;
	self.hud_flagflash.alignX = "center";
	self.hud_flagflash.alignY = "middle";
	self.hud_flagflash.horzAlign = "left";
	self.hud_flagflash.vertAlign = "top";
	self.hud_flagflash.alpha = 0;
	self.hud_flagflash.sort = 1;

	if(self.pers["team"] == "axis")
	{
		self.hud_flag setShader(level.hudflag_axis, iconSize, iconSize);
		self.hud_flagflash setShader(level.hudflagflash_axis, iconSize, iconSize);
	}
	else
	{
		assert(self.pers["team"] == "allies");
		self.hud_flag setShader(level.hudflag_allies, iconSize, iconSize);
		self.hud_flagflash setShader(level.hudflagflash_allies, iconSize, iconSize);
	}

	self.hud_flagflash fadeOverTime(.2);
	self.hud_flagflash.alpha = 1;

	self.hud_flag fadeOverTime(.2);
	self.hud_flag.alpha = 1;

	wait .2;
	
	if(isdefined(self.hud_flagflash))
	{
		self.hud_flagflash fadeOverTime(1);
		self.hud_flagflash.alpha = 0;
	}
}

createOwnHudIconOwn()
{
	iconSize = 40;

	self.hud_flagown = newClientHudElem(self);
	self.hud_flagown.x = 30;
	self.hud_flagown.y = 135;
	self.hud_flagown.alignX = "center";
	self.hud_flagown.alignY = "middle";
	self.hud_flagown.horzAlign = "left";
	self.hud_flagown.vertAlign = "top";
	self.hud_flagown.alpha = 0;

	self.hud_flagownflash = newClientHudElem(self);
	self.hud_flagownflash.x = 30;
	self.hud_flagownflash.y = 135;
	self.hud_flagownflash.alignX = "center";
	self.hud_flagownflash.alignY = "middle";
	self.hud_flagownflash.horzAlign = "left";
	self.hud_flagownflash.vertAlign = "top";
	self.hud_flagownflash.alpha = 0;
	self.hud_flagownflash.sort = 1;

	if(self.pers["team"] == "axis")
	{
		self.hud_flagown setShader(level.hudflag_axis, iconSize, iconSize);
		self.hud_flagownflash setShader(level.hudflagflash_axis, iconSize, iconSize);
	}
	else
	{
		assert(self.pers["team"] == "allies");
		self.hud_flagown setShader(level.hudflag_allies, iconSize, iconSize);
		self.hud_flagownflash setShader(level.hudflagflash_allies, iconSize, iconSize);
	}

	self.hud_flagownflash fadeOverTime(.2);
	self.hud_flagownflash.alpha = 1;

	self.hud_flagown fadeOverTime(.2);
	self.hud_flagown.alpha = 1;

	wait .2;
	
	if(isdefined(self.hud_flagownflash))
	{
		self.hud_flagownflash fadeOverTime(1);
		self.hud_flagownflash.alpha = 0;
	}
}

deleteHudIcon()
{
	if(isdefined(self.hud_flagflash))
		self.hud_flagflash destroy();
		
	if(isdefined(self.hud_flag))
		self.hud_flag destroy();
}

deleteOwnHudIcon()
{
	if(isdefined(self.hud_flagownflash))
		self.hud_flagownflash destroy();
		
	if(isdefined(self.hud_flagown))
		self.hud_flagown destroy();
}

createFlagWaypoint()
{
	if (! level.wwx_objindicator)
		return;

	self deleteFlagWaypoint();

	if (! level.objective_icon)
		return;

	waypoint = newHudElem();
	waypoint.x = self.origin[0];
	waypoint.y = self.origin[1];
	waypoint.z = self.origin[2] + 100;
	waypoint.alpha = .61;
	waypoint.archived = true;

	if(level.splitscreen)
		waypoint setShader(self.objpointflag, 14, 14);
	else
		waypoint setShader(self.objpointflag, 7, 7);

	waypoint setwaypoint(true);
	self.waypoint_flag = waypoint;
}

deleteFlagWaypoint()
{

	if(isdefined(self.waypoint_flag))
		self.waypoint_flag destroy();
}

createFlagMissingWaypoint()
{
	self deleteFlagMissingWaypoint();

	if (! level.objective_icon)
		return;

	waypoint = newHudElem();
	waypoint.x = self.home_origin[0];
	waypoint.y = self.home_origin[1];
	waypoint.z = self.home_origin[2] + 100;
	waypoint.alpha = .61;
	waypoint.archived = true;

	if(level.splitscreen)
		waypoint setShader(self.objpointflagmissing, 14, 14);
	else
		waypoint setShader(self.objpointflagmissing, 7, 7);

	waypoint setwaypoint(true);
	self.waypoint_base = waypoint;
}

deleteFlagMissingWaypoint()
{
	if(isdefined(self.waypoint_base))
		self.waypoint_base destroy();
}

playSoundOnPlayers(sound, team)
{
	players = getentarray("player", "classname");

	if(level.splitscreen)
	{
		if(isdefined(players[0]))
			players[0] playLocalSound(sound);
	}
	else
	{
		if(isdefined(team))
		{
			for(i = 0; i < players.size; i++)
			{
				if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == team))
					players[i] playLocalSound(sound);
			}
		}
		else
		{
			for(i = 0; i < players.size; i++)
				players[i] playLocalSound(sound);
		}
	}

	wait 1;	
	level notify ("psopdone");
}

printOnTeam(text, team, playername)
{
	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
	{
		if((isdefined(players[i].pers["team"])) && (players[i].pers["team"] == team))
			players[i] iprintln(text,playername);
	}
}

respawn_timer(delay)
{
	self endon("disconnect");

	self.WaitingToSpawn = true;

	if(level.respawndelay > 0)
	{
		if(!isdefined(self.respawntimer))
		{
			self.respawntimer = newClientHudElem(self);
			self.respawntimer.x = 0;
			self.respawntimer.y = -50;
			self.respawntimer.alignX = "center";
			self.respawntimer.alignY = "middle";
			self.respawntimer.horzAlign = "center_safearea";
			self.respawntimer.vertAlign = "center_safearea";
			self.respawntimer.alpha = 0;
			self.respawntimer.archived = false;
			self.respawntimer.font = "default";
			self.respawntimer.fontscale = 2;
			self.respawntimer.label = (&"MP_TIME_TILL_SPAWN");
			self.respawntimer setTimer (level.respawndelay + delay);
		}

		wait delay;
		self thread updateTimer();

		wait level.respawndelay;

		if(isdefined(self.respawntimer))
			self.respawntimer destroy();
	}

	self.WaitingToSpawn = undefined;
}

updateTimer()
{
	if(isdefined(self.respawntimer))
	{
		if(isdefined(self.pers["team"]) && (self.pers["team"] == "allies" || self.pers["team"] == "axis") && isdefined(self.pers["weapon"]))
			self.respawntimer.alpha = 1;
		else
			self.respawntimer.alpha = 0;
	}
}

iprintlnFIXED (locstring, player)
{
	if(level.wwx_linux_server >= 1)
		self iprintln (locstring, player.name);
	else
		self iprintln (locstring, player);
}

printOnTeamFIXED (locstring, team, player)
{
	if(level.wwx_linux_server >= 1)
		printOnTeam (locstring, team, player.name);
	else
		printOnTeam (locstring, team, player);
}

BlinkFlags()
{
	self endon ("disconnect");
	
	while (isdefined (self.flag) && isdefined (self.ownflag) && !level.wwx_ranksystem)
	{
		if (self.statusicon == level.hudflag_allies)
		self.statusicon = level.hudflag_axis;
		else
            self.statusicon = level.hudflag_allies;

		// 2 seconds wait ; the scoreboard is updated every 2 seconds anyway
		wait 2;
	}
}

CheckProtectedOwnFlag (victim_origin)
{
	flag = level.flags[self.pers["team"]];

	if (isdefined (flag.carrier))
	{
		// Flag is being carried
		
		if (flag.carrier == self)
			// No "self-assistance"
			return;
			
		if (flag.carrier.pers["team"] != self.pers["team"])
			// No assistance for ennemy carrier
			return;

		dist = distance (victim_origin, flag.carrier.origin);
		
		if (dist < level.flagprotectiondistance)
		{
                  if(level.wwx_linux_server >= 1)
                  {
			iprintln (&"MP_CTFB_ASSIST", self.name);
                  }
                  else
                  {
			iprintln (&"MP_CTFB_ASSIST", self);
                  }                
			self.score += level.points_assist - 1;
		}
		
		return;
	}

	if (flag.atbase)
		// Flag is at base
		dist = distance (victim_origin, flag.home_origin);
	else
		// Flag has been droppped by a player
		dist = distance (victim_origin, flag.origin);
	
	if (dist < level.flagprotectiondistance)
	{
            if(level.wwx_linux_server >= 1)
            {
		iprintln (&"MP_CTFB_DEFEND", self.name);
            }
            else
            {
		iprintln (&"MP_CTFB_DEFEND", self);
            }
		self.score += level.points_defend - 1;
	}
}