#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include maps\mp\gametypes\common_sd_sr;

// Rallypoints should be destroyed on leaving your team/getting killed
// Compass icons need to be looked at
// Doesn't seem to be setting angle on spawn so that you are facing your rallypoint

/*
	Search and Destroy
	Attackers objective: Bomb one of 2 positions
	Defenders objective: Defend these 2 positions / Defuse planted bombs
	Round ends:	When one team is eliminated, bomb explodes, bomb is defused, or roundlength time is reached
	Map ends:	When one team reaches the score limit, or time limit or round limit is reached
	Respawning:	Players remain dead for the round and will respawn at the beginning of the next round

	Level requirements
	------------------
		Allied Spawnpoints:
			classname		mp_sd_spawn_attacker
			Allied players spawn from these. Place at least 16 of these relatively close together.

		Axis Spawnpoints:
			classname		mp_sd_spawn_defender
			Axis players spawn from these. Place at least 16 of these relatively close together.

		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.

		Bombzones:
			classname					trigger_multiple
			targetname					bombzone
			script_gameobjectname		bombzone
			script_bombmode_original	<if defined this bombzone will be used in the original bomb mode>
			script_bombmode_single		<if defined this bombzone will be used in the single bomb mode>
			script_bombmode_dual		<if defined this bombzone will be used in the dual bomb mode>
			script_team					Set to allies or axis. This is used to set which team a bombzone is used by in dual bomb mode.
			script_label				Set to A or B. This sets the letter shown on the compass in original mode.
			This is a volume of space in which the bomb can planted. Must contain an origin brush.

		Bomb:
			classname				trigger_lookat
			targetname				bombtrigger
			script_gameobjectname	bombzone
			This should be a 16x16 unit trigger with an origin brush placed so that it's center lies on the bottom plane of the trigger.
			Must be in the level somewhere. This is the trigger that is used when defusing a bomb.
			It gets moved to the position of the planted bomb model.

	Level script requirements
	-------------------------
		Team Definitions:
			game["attackers"] = "allies";
			game["defenders"] = "axis";
			This sets which team is attacking and which team is defending. Attackers plant the bombs. Defenders protect the targets.

		Exploder Effects:
			Setting script_noteworthy on a bombzone trigger to an exploder group can be used to trigger additional effects.
*/

/*QUAKED mp_sd_spawn_attacker (0.0 1.0 0.0) (-16 -16 0) (16 16 72)
Attacking players spawn randomly at one of these positions at the beginning of a round.*/

/*QUAKED mp_sd_spawn_defender (1.0 0.0 0.0) (-16 -16 0) (16 16 72)
Defending players spawn randomly at one of these positions at the beginning of a round.*/

/*QUAKED mp_spawn (1.0 1.0 1.0) (-16 -16 0) (16 16 72)
Generic spawn.*/

main()
{
	if(getdvar("mapname") == "mp_background")
		return;
	
	maps\mp\gametypes\_globallogic::init();
	maps\mp\gametypes\_callbacksetup::SetupCallbacks();
	maps\mp\gametypes\_globallogic::SetupCallbacks();	
	
	if ( isUsingMatchRulesData() )
	{
		level.initializeMatchRules = ::initializeMatchRules;
		[[level.initializeMatchRules]]();
		level thread reInitializeMatchRulesOnMigration();	
	}
	else
	{
		registerRoundSwitchDvar( level.gameType, 3, 0, 9 );
		registerTimeLimitDvar( level.gameType, 2.5 );
		registerScoreLimitDvar( level.gameType, 1 );
		registerRoundLimitDvar( level.gameType, 0 );
		registerWinLimitDvar( level.gameType, 4 );
		registerNumLivesDvar( level.gameType, 1 );
		registerHalfTimeDvar( level.gameType, 0 );
		
		level.matchRules_damageMultiplier = 0;
		level.matchRules_vampirism = 0;	
	}
	
	level.objectiveBased = true;
	level.teamBased = true;
	level.onPrecacheGameType = ::onPrecacheGameType;
	level.onStartGameType = ::onStartGameType;
	level.getSpawnPoint = ::getSpawnPoint;
	level.onSpawnPlayer = ::onSpawnPlayer;
	level.onPlayerKilled = ::onPlayerKilled;
	level.onDeadEvent = ::onDeadEvent;
	level.onOneLeftEvent = ::onOneLeftEvent;
	level.onTimeLimit = ::onTimeLimit;
	level.onNormalDeath = ::onNormalDeath;
	level.gameModeMayDropWeapon = ::isPlayerOutsideOfAnyBombSite;
	
	level.allowLateComers = false;
	
	if ( level.matchRules_damageMultiplier || level.matchRules_vampirism )
		level.modifyPlayerDamage = maps\mp\gametypes\_damage::gamemodeModifyPlayerDamage;
	
	game["dialog"]["gametype"] = "sd_intro";

	if ( getDvarInt( "g_hardcore" ) )
		game["dialog"]["gametype"] = "hc_" + game["dialog"]["gametype"];

	game["dialog"]["offense_obj"] = "gbl_destroyobj";
	game["dialog"]["defense_obj"] = "gbl_defendobj";

	SetOmnvar( "ui_bomb_timer_endtime", 0 );

/#
		SetDevDvarIfUninitialized( "scr_sd_debugBombKillCamEnt", 0 );
#/
}


initializeMatchRules()
{
	//	set common values
	setCommonRulesFromMatchRulesData();
	
	//	set everything else (private match options, default .cfg file values, and what normally is registered in the 'else' below)
	roundLength = GetMatchRulesData( "sdData", "roundLength" );
	SetDynamicDvar( "scr_sd_timelimit", roundLength );
	registerTimeLimitDvar( "sd", roundLength );	
			
	roundSwitch = GetMatchRulesData( "sdData", "roundSwitch" );
	SetDynamicDvar( "scr_sd_roundswitch", roundSwitch );
	registerRoundSwitchDvar( "sd", roundSwitch, 0, 9 );
	
	winLimit = GetMatchRulesData( "commonOption", "scoreLimit" );
	SetDynamicDvar( "scr_sd_winlimit", winLimit );
	registerWinLimitDvar( "sd", winLimit );		
		
	SetDynamicDvar( "scr_sd_bombtimer", GetMatchRulesData( "sdData", "bombTimer" ) );
	SetDynamicDvar( "scr_sd_planttime", GetMatchRulesData( "sdData", "plantTime" ) );
	SetDynamicDvar( "scr_sd_defusetime", GetMatchRulesData( "sdData", "defuseTime" ) );
	SetDynamicDvar( "scr_sd_multibomb", GetMatchRulesData( "sdData", "multiBomb" ) );
	SetDynamicDvar( "scr_sd_silentplant", GetMatchRulesData( "sdData", "silentPlant" ) );
	
	SetDynamicDvar( "scr_sd_roundlimit", 0 );
	registerRoundLimitDvar( "sd", 0 );		
	SetDynamicDvar( "scr_sd_scorelimit", 1 );
	registerScoreLimitDvar( "sd", 1 );			
	SetDynamicDvar( "scr_sd_halftime", 0 );
	registerHalfTimeDvar( "sd", 0 );				
}


onStartGameType()
{
	if ( !isDefined( game["switchedsides"] ) )
		game["switchedsides"] = false;
	
	if ( game["switchedsides"] )
	{
		oldAttackers = game["attackers"];
		oldDefenders = game["defenders"];
		game["attackers"] = oldDefenders;
		game["defenders"] = oldAttackers;
	}
	
	setClientNameMode( "manual_change" );

	level._effect["bomb_explosion"] = loadfx("vfx/explosion/mp_gametype_bomb");
	level._effect["bomb_light_blinking"] = loadfx("vfx/lights/light_sdbomb_blinking");
	level._effect["bomb_light_planted"] = loadfx("vfx/lights/light_beacon_sdbomb");
	
	setObjectiveText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
	setObjectiveText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );

	if ( level.splitscreen )
	{
		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER" );
		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER" );
	}
	else
	{
		setObjectiveScoreText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_SCORE" );
		setObjectiveScoreText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_SCORE" );
	}
	setObjectiveHintText( game["attackers"], &"OBJECTIVES_SD_ATTACKER_HINT" );
	setObjectiveHintText( game["defenders"], &"OBJECTIVES_SD_DEFENDER_HINT" );
	
	initSpawns();
	
	allowed[0] = "sd";
	allowed[1] = "bombzone";
	allowed[2] = "blocker";
	maps\mp\gametypes\_gameobjects::main( allowed );
	
	thread updateGametypeDvars();
	
	//	because axis or allies may be attackers, special loadout has to be created on game start for this mode
	setSpecialLoadout();
	
	thread bombs();
}


initSpawns()
{
	level.spawnMins = ( 0, 0, 0 );
	level.spawnMaxs = ( 0, 0, 0 );	
	
	maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_sd_spawn_attacker" );
	maps\mp\gametypes\_spawnlogic::addStartSpawnPoints( "mp_sd_spawn_defender" );
	
	level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs );
	setMapCenter( level.mapCenter );
}


getSpawnPoint()
{
	spawnPointName = "mp_sd_spawn_defender";
	
	if( self.pers["team"] == game["attackers"] )
	{
		spawnPointName = "mp_sd_spawn_attacker";
	}

	spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( spawnPointName );
	assert( spawnPoints.size );
	
	spawnpoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_startSpawn( spawnPoints );
	
	self maps\mp\gametypes\_spawnlogic::recon_set_spawnpoint( spawnpoint );
	
	return spawnpoint;
}

onSpawnPlayer()
{
	is_respawning_with_bomb_carrier_class = IsDefined(self.isRespawningWithBombCarrierClass) && self.isRespawningWithBombCarrierClass;
	if ( IsGameParticipant( self ) )
	{
		self.isPlanting = false;
		self.isDefusing = false;
		if ( !is_respawning_with_bomb_carrier_class )
		{
			self.isBombCarrier = false;
			self.objective = 0;
		}
	}
	
	if ( IsPlayer(self) && !is_respawning_with_bomb_carrier_class )
	{
		if( level.multiBomb && self.pers[ "team" ] == game[ "attackers" ] )
			self SetClientOmnvar( "ui_carrying_bomb", true );
		else
			self SetClientOmnvar( "ui_carrying_bomb", false );
	}
	
	// set the extra score value for the scoreboard
	self setExtraScore0( 0 );
	if( IsDefined( self.pers[ "plants" ] ) )
		self setExtraScore0( self.pers[ "plants" ] );
	self setExtraScore1( 0 );
	if( IsDefined( self.pers[ "defuses" ] ) )
		self setExtraScore1( self.pers[ "defuses" ] );

	self.isRespawningWithBombCarrierClass = undefined;
	level notify ( "spawned_player" );
}


onPlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, killId)
{
	if( IsPlayer( self ) )
		self SetClientOmnvar( "ui_carrying_bomb", false );

	thread checkAllowSpectating();
}
