L4D2 Decrypted mutations

From Valve Developer Community
Jump to: navigation, search

Contents

Decrypted L4D2 Mutation Scripts

These are all official L4D2 mutation scripts and their included scripts. Most scripts have been decrypted on February 26th 2021 with L4D2 VScript Editor Beta 0.5 by Cynick and may be updated at any time.

Valve Mutations

L4d1

 
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//
//=============================================================================
Msg("Activating Mutation L4D1\n");

if ( !IsModelPrecached( "models/infected/smoker_l4d1.mdl" ) )
	PrecacheModel( "models/infected/smoker_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/boomer_l4d1.mdl" ) )
	PrecacheModel( "models/infected/boomer_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/hunter_l4d1.mdl" ) )
	PrecacheModel( "models/infected/hunter_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/hulk_l4d1.mdl" ) )
	PrecacheModel( "models/infected/hulk_l4d1.mdl" );

DirectorOptions <-
{
	ActiveChallenge = 1

	SpitterLimit = 0
	JockeyLimit = 0
	ChargerLimit = 0

	EscapeSpawnTanks = true

	weaponsToConvert =
	{
		weapon_shotgun_spas				= "weapon_autoshotgun_spawn"
		weapon_defibrillator			= "weapon_first_aid_kit_spawn"
		weapon_ammo_pack				= "weapon_first_aid_kit_spawn"
		weapon_sniper_awp				= "weapon_hunting_rifle_spawn"
		weapon_sniper_military			= "weapon_hunting_rifle_spawn"
		weapon_sniper_scout				= "weapon_hunting_rifle_spawn"
		weapon_vomitjar					= "weapon_molotov_spawn"
		weapon_adrenaline				= "weapon_pain_pills_spawn"
		weapon_pistol_magnum			= "weapon_pistol_spawn"
		weapon_shotgun_chrome			= "weapon_pumpshotgun_spawn"
		weapon_rifle_ak47				= "weapon_rifle_spawn"
		weapon_rifle_desert				= "weapon_rifle_spawn"
		weapon_rifle_sg552				= "weapon_rifle_spawn"
		weapon_smg_mp5					= "weapon_smg_spawn"
		weapon_smg_silenced				= "weapon_smg_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}

	weaponsToRemove =
	{
		weapon_rifle_m60 = 0
		weapon_grenade_launcher = 0
		weapon_chainsaw = 0
		weapon_melee = 0
		weapon_upgradepack_explosive = 0
		weapon_upgradepack_incendiary = 0
		upgrade_item = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	function ShouldAvoidItem( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return true;
		}
		return false;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	EntFire( "worldspawn", "AddOutput", "timeofday 0" );
	EntFire( "weapon_*", "AddOutput", "skin 0" );
	EntFire( "weapon_*", "AddOutput", "weaponskin -1" );
	EntFire( "trigger_upgrade_laser_sight", "Kill" );
	
	foreach( wep, val in DirectorOptions.weaponsToRemove )
		EntFire( wep + "_spawn", "Kill" );
	foreach( wep, val in DirectorOptions.weaponsToConvert )
	{
		local wep_spawner = null;
		while ( wep_spawner = Entities.FindByClassname( wep_spawner, wep + "_spawn" ) )
		{
			if ( wep_spawner.IsValid() )
			{
				local spawnTable =
				{
					origin = wep_spawner.GetOrigin(),
					angles = wep_spawner.GetAngles().ToKVString(),
					targetname = wep_spawner.GetName(),
					count = NetProps.GetPropInt( wep_spawner, "m_itemCount" ),
					spawnflags = NetProps.GetPropInt( wep_spawner, "m_spawnflags" )
				}
				wep_spawner.Kill();
				SpawnEntityFromTable(val, spawnTable);
			}
		}
	}
	
	if ( SessionState.ModeName == "l4d1coop" || SessionState.ModeName == "l4d1vs" )
	{
		if ( SessionState.MapName == "c8m5_rooftop" || SessionState.MapName == "c9m2_lots" || SessionState.MapName == "c10m5_houseboat"
			|| SessionState.MapName == "c11m5_runway" || SessionState.MapName == "c12m5_cornfield" )
		{
			local finale = Entities.FindByClassname( null, "trigger_finale" );
			if ( finale )
				NetProps.SetPropInt( finale, "m_type", 0 );
		}
		else if ( SessionState.MapName == "c10m4_mainstreet" )
		{
			local relay = Entities.FindByName( null, "forklift_relay" );
			if ( relay )
			{
				EntityOutputs.RemoveOutput( relay, "OnTrigger", "director", "BeginScript", "c10m4_onslaught" );
				EntityOutputs.AddOutput( relay, "OnTrigger", "director", "ForcePanicEvent", "", 9.0, -1 );
			}
			EntFire( "onslaught1", "Kill" );
		}
		else if ( SessionState.MapName == "c11m4_terminal" )
		{
			local van = Entities.FindByName( null, "van_button" );
			if ( van )
			{
				EntityOutputs.RemoveOutput( van, "OnPressed", "@director", "", "" );
				EntityOutputs.AddOutput( van, "OnPressed", "@director", "ForcePanicEvent", "", 3.0, -1 );
			}
			local relay = Entities.FindByName( null, "alarm_on_relay" );
			if ( relay )
			{
				EntityOutputs.RemoveOutput( relay, "OnTrigger", "@director", "", "" );
				EntityOutputs.RemoveOutput( relay, "OnTrigger", "alarm_safety_relay", "", "" );
				EntityOutputs.AddOutput( relay, "OnTrigger", "@director", "ForcePanicEvent", "", 0.0, -1 );
				EntityOutputs.AddOutput( relay, "OnTrigger", "alarm_off_relay", "Trigger", "", 15.0, -1 );
			}
			EntFire( "van_follow_trigger", "Kill" );
			EntFire( "van_endscript_relay", "Kill" );
		}
		else if ( SessionState.MapName == "c12m3_bridge" )
		{
			local relay = Entities.FindByName( null, "train_engine_relay" );
			if ( relay )
			{
				EntityOutputs.RemoveOutput( relay, "OnTrigger", "director", "BeginScript", "c12m3_onslaught" );
				EntityOutputs.AddOutput( relay, "OnTrigger", "director", "ForcePanicEvent", "", 2.0, -1 );
				EntFire( "zombie_spawn1", "Kill" );
			}
		}
		else if ( SessionState.MapName == "c12m4_barn" )
			EntFire( "window_trigger", "Kill" );
	}
}

function OnGameEvent_player_spawn( params )
{
	local player = GetPlayerFromUserID( params["userid"] );
	
	if ( ( !player ) || ( player.IsSurvivor() ) )
		return;
	
	local modelName = player.GetModelName();
	if ( ( modelName.find( "l4d1" ) != null ) || ( modelName == "models/infected/hulk_dlc3.mdl" ) )
		return;
	
	switch( player.GetZombieType() )
	{
		case 1:
		{
			player.SetModel( "models/infected/smoker_l4d1.mdl" );
			break;
		}
		case 2:
		{
			player.SetModel( "models/infected/boomer_l4d1.mdl" );
			break;
		}
		case 3:
		{
			player.SetModel( "models/infected/hunter_l4d1.mdl" );
			break;
		}
		case 8:
		{
			player.SetModel( "models/infected/hulk_l4d1.mdl" );
			break;
		}
		default:
			break;
	}
}

function OnGameEvent_player_death( params )
{
	if ( !("userid" in params) )
		return;
	
	local victim = GetPlayerFromUserID( params["userid"] );
	
	if ( ( !victim ) || ( !victim.IsSurvivor() ) )
		return;
	
	EntFire( "survivor_death_model", "BecomeRagdoll" );
}

L4d1coop - L4D1 Co-op

 
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//
//=============================================================================

IncludeScript( "l4d1" )

L4d1vs - L4D1 Versus

 
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//
//=============================================================================

IncludeScript( "l4d1" )

L4d1survival - L4D1 Survival

 
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//
//=============================================================================

IncludeScript( "l4d1" )

Mutation1 - Last Man on Earth

 
//-----------------------------------------------------
Msg("Activating Mutation 1\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_NoSurvivorBots = 1
	cm_CommonLimit = 0
	cm_DominatorLimit = 1
	cm_MaxSpecials = 2
	cm_SpecialRespawnInterval = 60
	cm_AutoReviveFromSpecialIncap = 1
	cm_AllowPillConversion = 0

	BoomerLimit = 0
	MobMaxPending = 0
	SurvivorMaxIncapacitatedCount = 1
	SpecialInitialSpawnDelayMin = 5
	SpecialInitialSpawnDelayMax = 30
	TankHitDamageModifierCoop = 0.5
	
	// convert items that aren't useful
	weaponsToConvert =
	{
		weapon_pipe_bomb =	"weapon_molotov_spawn"
		weapon_vomitjar =	"weapon_molotov_spawn"
		weapon_defibrillator =	"weapon_first_aid_kit_spawn"

		weapon_smg =		"weapon_rifle_spawn"
		weapon_pumpshotgun =	"weapon_autoshotgun_spawn"
		weapon_smg_silenced =	"weapon_rifle_desert_spawn"
		weapon_shotgun_chrome =	"weapon_shotgun_spas_spawn"
		weapon_smg_mp5 =	"weapon_rifle_sg552_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}	
}

function OnGameEvent_round_start_post_nav( params )
{
	local spawner = null;
	while ( spawner = Entities.FindByClassname( spawner, "info_zombie_spawn" ) )
	{
		if ( spawner.IsValid() )
		{
			local population = NetProps.GetPropString( spawner, "m_szPopulation" );
			
			if ( population == "boomer" || population == "hunter" || population == "smoker" || population == "jockey"
				|| population == "charger" || population == "spitter" || population == "new_special" || population == "church"
					|| population == "tank" || population == "witch" || population == "witch_bride" || population == "river_docks_trap" )
				continue;
			else
				spawner.Kill();
		}
	}
	
	if ( Director.GetMapName() == "c5m5_bridge" || Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 0;
	
	foreach( wep, val in DirectorOptions.weaponsToConvert )
	{
		local wep_spawner = null;
		while ( wep_spawner = Entities.FindByClassname( wep_spawner, wep + "_spawn" ) )
		{
			if ( wep_spawner.IsValid() )
			{
				local spawnTable =
				{
					origin = wep_spawner.GetOrigin(),
					angles = wep_spawner.GetAngles().ToKVString(),
					targetname = wep_spawner.GetName(),
					count = NetProps.GetPropInt( wep_spawner, "m_itemCount" ),
					spawnflags = NetProps.GetPropInt( wep_spawner, "m_spawnflags" )
				}
				wep_spawner.Kill();
				SpawnEntityFromTable(val, spawnTable);
			}
		}
	}
}

function OnGameEvent_finale_start( params )
{
	if ( Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 2;
}

function OnGameEvent_gauntlet_finale_start( params )
{
	if ( Director.GetMapName() == "c5m5_bridge" )
		DirectorOptions.cm_MaxSpecials = 2;
}

function Update()
{
	if ( Director.GetCommonInfectedCount() > 0 )
	{
		local infected = null;
		while ( infected = Entities.FindByClassname( infected, "infected" ) )
		{
			if ( infected.IsValid() )
				infected.Kill();
		}
	}
}

Mutation2 - Headshot!

 
//-----------------------------------------------------
Msg("Activating Mutation 2\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_HeadshotOnly = 1
}

Mutation3 - Bleed Out

 
//-----------------------------------------------------
Msg("Activating Mutation 3\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	weaponsToConvert =
	{
		weapon_first_aid_kit = "weapon_pain_pills_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}	

	// Challenge vars
	cm_TempHealthOnly = 1
	cm_AllowPillConversion = 0
	cm_ShouldHurry = 1
	cm_MaxSpecials = 4
	cm_SpecialRespawnInterval = 45
	cm_WanderingZombieDensityModifier = 0.003

	// Global vars
	MobSpawnMinTime = 5
	MobSpawnMaxTime = 10
	MobMinSize = 10
	MobMaxSize = 15
	MobMaxPending = 30
	SustainPeakMinTime = 10
	SustainPeakMaxTime = 15
	IntensityRelaxThreshold = 0.95
	RelaxMinInterval = 3
	RelaxMaxInterval = 5
	RelaxMaxFlowTravel = 50
	PreferredMobDirection = SPAWN_BEHIND_SURVIVORS

	TempHealthDecayRate = 0.001
	function RecalculateHealthDecay()
	{
		if ( Director.HasAnySurvivorLeftSafeArea() )
		{
			TempHealthDecayRate = 0.27 // pain_pills_decay_rate default
		}
	}
}

function Update()
{
	DirectorOptions.RecalculateHealthDecay();
}

Mutation4 - Hard Eight

 
//-----------------------------------------------------
Msg("Activating Mutation 4\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_SpecialRespawnInterval = 15
	cm_MaxSpecials = 8
	cm_BaseSpecialLimit = 2

	DominatorLimit = 8
}

Mutation5 - Four Swordsmen

 
//-----------------------------------------------------
Msg("Activating Mutation 5\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_CommonLimit = 0
	cm_DominatorLimit = 8
	cm_MaxSpecials = 8
	cm_SpecialRespawnInterval = 15

	SpecialInitialSpawnDelayMin = 5
	SpecialInitialSpawnDelayMax = 30
	
	// convert items that aren't useful
	weaponsToConvert =
	{
		weapon_pipe_bomb =	"weapon_molotov_spawn"
		weapon_vomitjar =	"weapon_molotov_spawn"
		weapon_defibrillator =	"weapon_first_aid_kit_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}	

	weaponsToRemove =
	{
		weapon_pistol = 0
		weapon_pistol_magnum = 0
		weapon_smg = 0
		weapon_pumpshotgun = 0
		weapon_autoshotgun = 0
		weapon_rifle = 0
		weapon_hunting_rifle = 0
		weapon_smg_silenced = 0
		weapon_shotgun_chrome = 0
		weapon_rifle_desert = 0
		weapon_sniper_military = 0
		weapon_shotgun_spas = 0
		weapon_grenade_launcher = 0
		weapon_rifle_ak47 = 0
		weapon_smg_mp5 = 0
		weapon_rifle_sg552 = 0
		weapon_sniper_awp = 0
		weapon_sniper_scout = 0
		weapon_rifle_m60 = 0
		weapon_melee = 0
		weapon_chainsaw = 0
		weapon_upgradepack_incendiary = 0
		weapon_upgradepack_explosive = 0
		ammo = 0
		upgrade_item = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	function ShouldAvoidItem( classname )
	{
		if ( ( classname != "weapon_melee" ) && ( classname in weaponsToRemove ) )
		{
			return true;
		}
		return false;
	}

	DefaultItems =
	[
		"katana",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	local spawner = null;
	while ( spawner = Entities.FindByClassname( spawner, "info_zombie_spawn" ) )
	{
		if ( spawner.IsValid() )
		{
			local population = NetProps.GetPropString( spawner, "m_szPopulation" );
			
			if ( population == "boomer" || population == "hunter" || population == "smoker" || population == "jockey"
				|| population == "charger" || population == "spitter" || population == "new_special" || population == "church"
					|| population == "tank" || population == "witch" || population == "witch_bride" || population == "river_docks_trap" )
				continue;
			else
				spawner.Kill();
		}
	}
	
	if ( Director.GetMapName() == "c5m5_bridge" || Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 0;
	
	EntFire( "weapon_spawn", "Kill" );
	foreach( wep, val in DirectorOptions.weaponsToRemove )
		EntFire( wep + "_spawn", "Kill" );
}

function OnGameEvent_finale_start( params )
{
	if ( Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 8;
}

function OnGameEvent_gauntlet_finale_start( params )
{
	if ( Director.GetMapName() == "c5m5_bridge" )
		DirectorOptions.cm_MaxSpecials = 8;
}

function Update()
{
	if ( Director.GetCommonInfectedCount() > 0 )
	{
		local infected = null;
		while ( infected = Entities.FindByClassname( infected, "infected" ) )
		{
			if ( infected.IsValid() )
				infected.Kill();
		}
	}
}

Mutation7 - Chainsaw Massacre

 
//-----------------------------------------------------
Msg("Activating Mutation 7\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_InfiniteFuel = 1
	cm_ShouldHurry = 1

	weaponsToRemove =
	{
		weapon_pistol = 0
		weapon_pistol_magnum = 0
		weapon_smg = 0
		weapon_pumpshotgun = 0
		weapon_autoshotgun = 0
		weapon_rifle = 0
		weapon_hunting_rifle = 0
		weapon_smg_silenced = 0
		weapon_shotgun_chrome = 0
		weapon_rifle_desert = 0
		weapon_sniper_military = 0
		weapon_shotgun_spas = 0
		weapon_grenade_launcher = 0
		weapon_rifle_ak47 = 0
		weapon_smg_mp5 = 0
		weapon_rifle_sg552 = 0
		weapon_sniper_awp = 0
		weapon_sniper_scout = 0
		weapon_rifle_m60 = 0
		weapon_melee = 0
		weapon_chainsaw = 0
		weapon_upgradepack_incendiary = 0
		weapon_upgradepack_explosive = 0
		ammo = 0
		upgrade_item = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	function ShouldAvoidItem( classname )
	{
		if ( ( classname != "weapon_chainsaw" ) && ( classname in weaponsToRemove ) )
		{
			return true;
		}
		return false;
	}

	DefaultItems =
	[
		"weapon_chainsaw",
		"weapon_pistol",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	EntFire( "weapon_spawn", "Kill" );
	foreach( wep, val in DirectorOptions.weaponsToRemove )
		EntFire( wep + "_spawn", "Kill" );
}

Mutation8 - Iron Man

 
//-----------------------------------------------------
Msg("Activating Mutation 8\n");


DirectorOptions <- 
{
	ActiveChallenge = 1

	cm_AllowSurvivorRescue = 0

	weaponsToRemove =
	{
		ammo = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}	
}

Mutation9 - Last Gnome On Earth

 
//-----------------------------------------------------
Msg("Activating Mutation 9\n");


DirectorOptions <- 
{
	ActiveChallenge = 1

	cm_VIPTarget = 1
	cm_ShouldHurry = 1
}

Mutation10 - Room For One

 
//-----------------------------------------------------
Msg("Activating Mutation 10\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_FirstManOut = 1
}

Mutation11 - Healthpackalypse!

 
//-----------------------------------------------------
Msg("Activating Mutation 11\n");

DirectorOptions <-
{
	ActiveChallenge = 1

	weaponsToRemove =
	{
		weapon_first_aid_kit = 0
		weapon_pain_pills = 0
		weapon_adrenaline = 0
		weapon_defibrillator = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}		
}

Mutation12 - Realism Versus

 
//-----------------------------------------------------
Msg("Activating Mutation 12\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_AllowPillConversion = 0

	ZombieGhostDelayMin = 15
	ZombieGhostDelayMax = 25

	weaponsToRemove =
	{
		weapon_first_aid_kit = 0
		weapon_defibrillator = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}		

	DefaultItems =
	[
		"weapon_first_aid_kit",
		"weapon_pistol",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}	
}

Mutation13 - Follow the Liter

 
//-----------------------------------------------------
Msg("Activating Mutation 13\n");


DirectorOptions <- 
{
	ActiveChallenge = 1

	cm_SingleScavengeCluster = 1

	ScavengeScoreBonusTime = 30
}

Mutation14 - Gib Fest

 
//-----------------------------------------------------
Msg("Activating Mutation 14\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	weaponsToRemove =
	{
		weapon_pistol = 0
		weapon_pistol_magnum = 0
		weapon_smg = 0
		weapon_pumpshotgun = 0
		weapon_autoshotgun = 0
		weapon_rifle = 0
		weapon_hunting_rifle = 0
		weapon_smg_silenced = 0
		weapon_shotgun_chrome = 0
		weapon_rifle_desert = 0
		weapon_sniper_military = 0
		weapon_shotgun_spas = 0
		weapon_grenade_launcher = 0
		weapon_rifle_ak47 = 0
		weapon_smg_mp5 = 0
		weapon_rifle_sg552 = 0
		weapon_sniper_awp = 0
		weapon_sniper_scout = 0
		weapon_rifle_m60 = 0
		weapon_melee = 0
		weapon_chainsaw = 0
		ammo = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	function ShouldAvoidItem( classname )
	{
		if ( ( classname != "weapon_rifle_m60" && classname != "weapon_pistol_magnum" ) && ( classname in weaponsToRemove ) )
		{
			return true;
		}
		return false;
	}

	DefaultItems =
	[
		"weapon_rifle_m60",
		"weapon_pistol_magnum",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	EntFire( "weapon_spawn", "Kill" );
	foreach( wep, val in DirectorOptions.weaponsToRemove )
		EntFire( wep + "_spawn", "Kill" );
}

Mutation15 - Versus Survival

 
//-----------------------------------------------------
Msg("Activating Mutation 15\n");


DirectorOptions <- 
{
	ActiveChallenge = 1

	cm_ProhibitBosses = 0
	cm_CommonLimit = 25
	cm_TankLimit = 1
	ZombieTankHealth = 2667

	SurvivalSetupTime = 90

	weaponsToRemove =
	{
		weapon_upgradepack_explosive = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}
}

function OnGameEvent_survival_round_start( params )
{
	EntFire( "info_director", "PanicEvent" );
	
	if ( SessionState.MapName == "c1m2_steets" )
		EntFire( "store_doors", "Open" );
	else if ( SessionState.MapName == "c7m1_docks" )
	{
		EntFire( "tankdoorin", "Open" );
		EntFire( "tankdoorin_button", "Kill" );
		EntFire( "tank_sound_timer", "Disable" );
		EntFire( "doorsound", "PlaySound" );
		EntFire( "tank_fog", "Enable" );
		EntFire( "tank_fog", "Disable", "", 0.5 );
		EntFire( "big_splash", "Start" );
		EntFire( "big_splash", "Stop", "", 2 );
		EntFire( "coop_tank", "Trigger" );
		EntFire( "radio_game_event", "Kill" );
		EntFire( "tank_door_clip", "Kill" );
		EntFire( "director", "EnableTankFrustration" );
		EntFire( "battlefield_cleared", "UnblockNav", "", 60 );
		EntFire( "tank_car_camera_clip", "Kill" );
	}
	else if ( SessionState.MapName == "c11m5_runway" )
		EntFire( "planecrash_trigger", "Trigger", "", 16 );
	else if ( SessionState.MapName == "c12m2_traintunnel" )
		EntFire( "emergency_door", "Open" );
}

Mutation16 - Hunting Party

 
//-----------------------------------------------------
Msg("Activating Mutation 16\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_SpecialSlotCountdownTime = 15
	cm_SpecialRespawnInterval = 1
	cm_MaxSpecials = 4

	HunterLimit = 4
	BoomerLimit = 0
	SmokerLimit = 0
	SpitterLimit = 0
	ChargerLimit = 0
	JockeyLimit = 0
	
	DominatorLimit = 4
}

Mutation17 - Lone Gunman

 
//-----------------------------------------------------
Msg("Activating Mutation 17\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_NoSurvivorBots = 1

	cm_CommonLimit = 10
	cm_BaseCommonAttackDamage = 15
	cm_WanderingZombieDensityModifier = 0.015

	HunterLimit = 0
	SmokerLimit = 0
	ChargerLimit = 0
	JockeyLimit = 0
	SpitterLimit = 0

	weaponsToRemove =
	{
		weapon_pistol = 0
		weapon_smg = 0
		weapon_pumpshotgun = 0
		weapon_autoshotgun = 0
		weapon_rifle = 0
		weapon_hunting_rifle = 0
		weapon_smg_silenced = 0
		weapon_shotgun_chrome = 0
		weapon_rifle_desert = 0
		weapon_sniper_military = 0
		weapon_shotgun_spas = 0
		weapon_grenade_launcher = 0
		weapon_rifle_ak47 = 0
		weapon_smg_mp5 = 0
		weapon_rifle_sg552 = 0
		weapon_sniper_awp = 0
		weapon_sniper_scout = 0
		weapon_rifle_m60 = 0
		weapon_melee = 0
		weapon_chainsaw = 0
		weapon_rifle_m60 = 0
		ammo = 0
		upgrade_item = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	DefaultItems =
	[
		"weapon_pistol_magnum",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	EntFire( "weapon_spawn", "Kill" );
	foreach( wep, val in DirectorOptions.weaponsToRemove )
		EntFire( wep + "_spawn", "Kill" );
}

Mutation18 - Bleed Out Versus

 
//-----------------------------------------------------
Msg("Activating Mutation 18\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	weaponsToConvert =
	{
		weapon_first_aid_kit = "weapon_pain_pills_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}	

	// Challenge vars
	cm_TempHealthOnly = 1
	cm_AllowPillConversion = 0
	cm_ShouldHurry = 1

	TempHealthDecayRate = 0.001
	function RecalculateHealthDecay()
	{
		if ( Director.HasAnySurvivorLeftSafeArea() )
		{
			TempHealthDecayRate = 0.27 // pain_pills_decay_rate default
		}
	}
}

function Update()
{
	DirectorOptions.RecalculateHealthDecay();
}

Mutation19 - Taaannnk!!

 
//-----------------------------------------------------
Msg("Activating Mutation 19\n");


DirectorOptions <-
{
	ActiveChallenge = 1

//	cm_frustrationTimer = 0
	cm_TankRun = 1
	cm_ShouldHurry = 1
	cm_AutoSpawnInfectedGhosts = 1

	PreferredSpecialDirection = SPAWN_BEHIND_SURVIVORS
	BehindSurvivorsSpawnDistance = 2000
	TankRunSpawnDelay = 15

	MobMaxPending = 0

	// Always convert to the TANK!!!
	function ConvertZombieClass( iClass )
	{
		return 8;
	}	

	weaponsToConvert =
	{
		weapon_first_aid_kit = "weapon_pain_pills_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}	

}

Mutation20 - Healing Gnome

 
//-----------------------------------------------------
Msg("Activating Mutation 20\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	weaponsToRemove =
	{
		weapon_first_aid_kit = 0
		weapon_pain_pills = 0
		weapon_adrenaline = 0
	}

	function AllowWeaponSpawn( classname )
	{
		if ( classname in weaponsToRemove )
		{
			return false;
		}
		return true;
	}

	// Challenge vars
	cm_TempHealthOnly = 1
	cm_AllowPillConversion = 0
	cm_HealingGnome = 1
	
	TempHealthDecayRate = 0.001
	function RecalculateHealthDecay()
	{
		if ( Director.HasAnySurvivorLeftSafeArea() )
		{
			TempHealthDecayRate = 0.27 // pain_pills_decay_rate default
		}
	}
}

function Update()
{
	DirectorOptions.RecalculateHealthDecay();
}

RocketDude

Technically, RocketDude was made by community members for the "The Last Stand" update, but listed as official because it is an official mutation.

 
//****************************************************************************************
//																						//
//									rocketDude.nut (mainfile)							//
//																						//
//****************************************************************************************

Msg("Activating RocketDude By ReneTM \n")

::rocketdude_version	<- "v1.7.7 build: 17:07:07 Feb 07 2021"
::mapName				<- Director.GetMapName().tolower()
::survivorSet			<- Director.GetSurvivorSet()
local grenadeData = {}




// Different scripts 2 include
// ----------------------------------------------------------------------------------------------------------------------------

IncludeScript("rocketdude/rd_debug")
IncludeScript("rocketdude/rd_utils")
IncludeScript("rocketdude/rd_melee_getter")
IncludeScript("rocketdude/rd_director")
IncludeScript("rocketdude/rd_damage_controll")
IncludeScript("rocketdude/rd_detonation_analysis")
IncludeScript("rocketdude/rd_meds")
IncludeScript("rocketdude/rd_events")
IncludeScript("rocketdude/rd_last_chance")
IncludeScript("rocketdude/rd_decals")
IncludeScript("rocketdude/rd_map_specifics")
IncludeScript("rocketdude/rd_custom_map_support")
IncludeScript("rocketdude/rd_saferoom_timer")
IncludeScript("rocketdude/rd_speedrun_mode")
IncludeScript("rocketdude/rd_mode_description")
IncludeScript("rocketdude/rd_hud_controller")




// Precache models and sounds
// ----------------------------------------------------------------------------------------------------------------------------

precacheSurvivorModels()

precacheRocketDudeModels()

precacheSounds()




// Creates a bullet time when the previous one is atleast 32 seconds ago.
// When this condition is met bullet time will occur with a probability of 3% 
// ----------------------------------------------------------------------------------------------------------------------------

local lastBulletTime = Time()
local lastDiceTime = Time()

::GLOBALS <-
{
	allowBulletTime = false
}

function bulletTime(){
	if(GLOBALS.allowBulletTime){
		if(Time() > lastBulletTime + 32){
			if(Time() >= lastDiceTime + 2){
				if(rollDice(3)){
					lastBulletTime = Time()
					DoEntFire( "!self", "Start", "", 0, timeScaler, timeScaler )
					DoEntFire( "!self", "Stop", "", 1, timeScaler, timeScaler )
				}
				lastDiceTime = Time()
			}
		}
	}
}

function saveGlobals(){
	SaveTable("GLOBAL_SAVINGS", GLOBALS)
}

function restoreGlobals(){
	RestoreTable("GLOBAL_SAVINGS", GLOBALS)
}




// When an instance of a grenade launcher projectile stops existing "doRocketJump" gets called
// ----------------------------------------------------------------------------------------------------------------------------

function grenadeExplodeEvent( impact ){
	foreach( player in getSurvivorsInRange( impact ) ){
		if(player.IsValid()){
			doRocketJump(impact, player)
		}
	}
}




// Returns an array of players within the blast radius
// ----------------------------------------------------------------------------------------------------------------------------

function getSurvivorsInRange(pos){
	local player = null
	while(player = Entities.FindByClassnameWithin(player, "player", pos, 160)){
		if(!player.IsDead()){
			if(!player.IsIncapacitated()){
				yield player
			}
		}
	}
}




// Compares current position of a projectile with the previous one. Force it to explode when it got stuck on prop_dynamic
// ----------------------------------------------------------------------------------------------------------------------------

function dynamicPropCheck(grenade){
	if(grenade in grenadeData){
		if(grenade.IsValid()){
			if((grenadeData[grenade] - grenade.GetOrigin()).Length() < 1){
				NetProps.SetPropInt(grenade, "m_takedamage", 1)
				grenade.TakeDamage(1337, 2, null)
			}	
		}
	}
}




// Get's fired 'OnGameplayStart' (usually after every single loadingscreen)
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameplayStart(){
	
	/* CREATE MUSHROOMS */
	if(IsValveMap()){
		spawnMushrooms()
	}
	
	/* SPAWN MAP SIDED MUSHROOMS */
	spawnMapSidedMushrooms()
	
	/* SET PLAYERS MAX HEALTH AND CURRENT HEALTH TO 200 */
	setPlayersHealth()
	
	/* GENERAL SETTINGS */
	checkCvars()

	/* CREATE BULLET TIME */
	createBulletTimerEntity()

	/* KILL ALL DEATH CAMS */
	removeDeathFallCameras()
	
	/* CREATE THINK TIMER */
	createThinkTimer()

	/* RESTORE SETTINGS LIKE BULLET TIME 1/0 */
	restoreGlobals()
}

::fixEntitiesRemoved <- false

::killFixEntities <- function(){
	if(!fixEntitiesRemoved){
		EntFire( "anv_mapfixes*", "Kill" )
		EntFire( "env_player_blocker", "Kill" )
		EntFire( "rene_relay", "Trigger" )
		fixEntitiesRemoved = true
	}
}




// Called for every player within the detonation radius, it will launch the player in the calculated direction
// ----------------------------------------------------------------------------------------------------------------------------

function doRocketJump(detonationPos, player){

	local hitSurface = getSurfaceValue(detonationPos, player)
	local ignoreDistance = 160
	local playerEyes = player.EyePosition()
	local finalVector = null
	
	local detonationDistance = (detonationPos - playerEyes).Length()
	local playerIsMidAir = NetProps.GetPropInt(player, "m_hGroundEntity") & 1
	local midAirFactor = 0
	local boostdirection = (detonationPos - playerEyes) * - 1
	local eyeToSurface = ((detonationPos - playerEyes).Length())
	local distanceFactor = (160 - eyeToSurface) / 10
	
	// WALL OR FLOOR ?
	if(hitSurface == "WALL"){
		distanceFactor *= 1.5
	}else{
		distanceFactor *= 1.4
	}
	
	if(detonationDistance <= ignoreDistance){
		if(playerIsMidAir){
			midAirFactor = 1
			finalVector = (player.GetVelocity() + boostdirection * midAirFactor * distanceFactor) 
		}else{
			midAirFactor = 0.5
			finalVector = (player.GetVelocity() + boostdirection * midAirFactor * distanceFactor)
		}
		player.SetVelocity(finalVector)
	}
}




// 1. Save current origin of projectiles
// 2. Check if projectile is stuck to prop_dynamic
// 3. Projectiles from bots are ignored ( just in case )
// 4. If the player enabled auto bhop ( by using green mushroom ) use another projectile model and set it to glowing
// 5. Get rockets which travel in a straight line
// 6. Check for invalid rockets and fire grenadeExplodeEvent
// ----------------------------------------------------------------------------------------------------------------------------

local grenadeColor = GetColorInt(Vector(64,64,64))
local grenadeGlowColor = GetColorInt(Vector(255,16,16))

function ProjectileGenerator(){
	local proj = null
	while(proj = Entities.FindByClassname(proj, "grenade_launcher_projectile")){
		yield proj
	}
}

function GrenadeListener(){
	local ent = null
	foreach(ent in ProjectileGenerator()){
		dynamicPropCheck(ent)
		if(!IsPlayerABot(NetProps.GetPropEntity(ent, "m_hThrower"))){
			grenadeData[ent] <- ent.GetOrigin()
		}
	
		local scope = GetValidatedScriptScope(ent)
	
		// Projectile model and color
		if(!("modelChanged" in scope)){
			if(NetProps.GetPropEntity(ent, "m_hThrower") in bunnyPlayers){
				ent.SetModel("models/w_models/weapons/w_rd_grenade_scale_x4_burn.mdl")
			}else{
				ent.SetModel("models/w_models/weapons/w_rd_grenade_scale_x4.mdl")
			}
			NetProps.SetPropInt(ent, "m_clrRender", grenadeColor)
			scope["modelChanged"] <- true
		}

		if(!("creationTimestamp" in scope)){
			scope["creationTimestamp"] <- Time()
		}
	
		// Projectile Glow
		if(Time() > scope["creationTimestamp"] + 0.12){
			if(!("glowEnabled" in scope)){
				if(NetProps.GetPropEntity(ent, "m_hThrower") in bunnyPlayers){
					NetProps.SetPropInt(ent, "m_Glow.m_glowColorOverride", grenadeGlowColor)
					NetProps.SetPropInt(ent, "m_Glow.m_nGlowRangeMin", 32)
					NetProps.SetPropInt(ent, "m_Glow.m_nGlowRange", 8192)
					NetProps.SetPropInt(ent, "m_Glow.m_iGlowType", 3)
					NetProps.SetPropInt(ent, "m_Glow.m_bFlashing", 1)
					scope["glowEnabled"] <- true
				}
			}
		}
		
		// Let rockets travel in a straight line like in TF2
		// Another method would be to change the ent´s gravity.
		// But this would result in reflecting projectiles
		// NetProps.SetPropFloat(nade, "m_flGravity", 0.00000001)
		
		if(!("first_dir_vec" in scope)){
			scope["first_dir_vec"] <- ent.GetVelocity()
			ent.SetVelocity(scope["first_dir_vec"])
		}else{
			ent.SetVelocity(scope["first_dir_vec"])
		}
	}

	// Check if saved instances are still valid. Fire "grenadeExplodeEvent" when this is not the case anymore 
	foreach(grenade, origin in grenadeData){
		if(!grenade.IsValid()){
			grenadeExplodeEvent(origin)
			grenadeData.rawdelete(grenade)
		}
	}
}




// Disable player´s ledge hang, set his max health to 200 and disable fall damage crack
// ----------------------------------------------------------------------------------------------------------------------------

local PlayerSettingsCheckTime = Time()
function PlayerSettings(){
	if(Time() > PlayerSettingsCheckTime + 4){
		foreach(player in GetSurvivors()){
			DoEntFire("!self", "DisableLedgeHang", "", 0.0, player, player)
			DoEntFire("!self", "ignorefalldamagewithoutreset", "99999", 0.0, player, player)
			//
			if(NetProps.GetPropInt(player, "m_iMaxHealth") != 200){
				NetProps.SetPropInt(player, "m_iMaxHealth", 200)
			}
			PlayerSettingsCheckTime = Time()
		}
	}
}


function setPlayersHealth(){
	foreach(player in GetSurvivors()){
		NetProps.SetPropInt(player, "m_iMaxHealth", 200)
		NetProps.SetPropInt(player, "m_iHealth", 200)
	}
}




// While the player´s primary and secondary weapon still have infinite ammo we want to remove used items from player inventory
// Since players are able to receive throwables from mushrooms we need to check if any survivor is standing right on a mushroom
// ----------------------------------------------------------------------------------------------------------------------------

function projectileListener(){
	local projectiles = [ "vomitjar_projectile", "molotov_projectile", "pipe_bomb_projectile" ]
	foreach(projectile in projectiles){
		local throwable = null
		while(throwable = Entities.FindByClassname(throwable, projectile)){
			if(throwable.IsValid()){
				local scope = GetValidatedScriptScope(throwable)
				if(!("inv_edited" in scope)){
					local invTable = {}
					local player = NetProps.GetPropEntity(throwable, "m_hThrower")
					// Special case for c4m3_sugarmill_b ( mapsided projectiles which destroys stuff )
					if(player == null || player.GetClassname() == "pipe_bomb_projectile"){
						return
					}
					GetInvTable(player, invTable)
					if("slot2" in invTable){
						invTable.slot2.Kill()
						scope["inv_edited"] <- true
					}

					foreach(trigger in medkit_triggers){
						DoEntFire("!self", "TouchTest", "", 0.03, trigger, trigger)
					}
				}
			}
		}
	}
}




// Check if mushrooms can be reactivated
// ----------------------------------------------------------------------------------------------------------------------------

function updateMushroomTrigger(){
	foreach(trigger in medkit_triggers){
		
		local scope = GetValidatedScriptScope(trigger)

		if(Time() >= scope.usetime + scope.restoreTime){
			if(scope.usable == false){
				scope.usetime = Time() - scope.restoreTime
				setMedVisibility(1, scope.model)
				scope.usable = true
				DoEntFire("!self", "TouchTest", "", 0, trigger, trigger)
			}
		}
	}
}




// Hold space for auto-bhop ( if player used bhop mushroom )
// ----------------------------------------------------------------------------------------------------------------------------

::bunnyPlayers <- {}

function autobhop(){
	foreach(player,ent in bunnyPlayers){
		if(ent.IsValid()){
			if(!(NetProps.GetPropInt(ent, "m_fFlags") & 1) && NetProps.GetPropInt(ent, "movetype") == 2){
				if(ent.GetButtonMask() & 2){
					ent.OverrideFriction(0.033, 0)
				}
				NetProps.SetPropInt(ent, "m_afButtonDisabled", NetProps.GetPropInt(ent, "m_afButtonDisabled") | 2)
			}else{
				NetProps.SetPropInt(ent, "m_afButtonDisabled", NetProps.GetPropInt(ent, "m_afButtonDisabled") & ~2)
			}
		}else{
			bunnyPlayers.rawdelete(player)
		}
	}
}








// Get's fired every tick from a timer
// ----------------------------------------------------------------------------------------------------------------------------

function Think(){
	checkCvars()
	GrenadeListener()
	PlayerSettings()
	projectileListener()
	updateMushroomTrigger()
	autobhop()
	PlayerFunctions()
	lastChanceCountDown()
	tankrockListener()
	safeRoomTimer()
}

RocketDude Additional Scripts

These scripts are all included in the main RocketDude script.

rd_custom_map_support
 
//****************************************************************************************
//																						//
//								rd_custom_map_support.nut								//
//																						//
//****************************************************************************************




// Spawn mushrooms from map entities 
// ----------------------------------------------------------------------------------------------------------------------------

spawnMapSidedMushrooms <- function(){
	
	local mushroomTarget = null

	local types = [ "tiny", "small", "medium", "large", "bh", "exp", "item" ]
	
	foreach(type in types){
		while(mushroomTarget = Entities.FindByName(mushroomTarget, "rd_mushroom_" + type)){
			createRD_Medkit(mushroomTarget.GetOrigin(), mushroomTarget.GetAngles().ToKVString(), false, shroomProperties[type])
		}
	}
	
	foreach(type in types){
		while(mushroomTarget = Entities.FindByName(mushroomTarget, "rd_mushroom_" + type + "_rotating")){
			createRD_Medkit(mushroomTarget.GetOrigin(), mushroomTarget.GetAngles().ToKVString(), true, shroomProperties[type])
		}
	}
}




// Timers and stats
// ----------------------------------------------------------------------------------------------------------------------------

::resetPlayerStats <- function(){
	if(activator.IsValid()){
		if(activator in PlayerTimeData){
			if(activator.GetZombieType() == ZombieTypes.SURVIVOR){
				local prevBest = PlayerTimeData[activator].time_best
				PlayerTimeData[activator] <- { timerActive = false, finished = false, startTime = Time(), endTime = Time(), time_best = prevBest, ticks = 0, seconds = 0 }
				ClientPrint(activator, 5, BLUE + activator.GetPlayerName() + " | 00:00")
				EmitAmbientSoundOn("ui/littlereward.wav", 0.5, 100, 110, activator)
			}
		}
	}
}

::startTimer <- function(){
	if(activator.IsValid()){
		if(activator in PlayerTimeData){
			if(activator.GetZombieType() == ZombieTypes.SURVIVOR){
				resetPlayerStats()
				PlayerTimeData[activator].timerActive = true
			}
		}
	}
}

::mapFinished <- function(){
	
	if(PlayerTimeData[activator].finished == true){
		return
	}
	
	printFinalGroundTime(activator)
	PlayerTimeData[activator].finished = true
	resetPlayerStats()
	
	local playerSpawn = Entities.FindByName(null, "rd_player_start")
	if(playerSpawn != null){
		activator.SetOrigin(playerSpawn.GetOrigin())
	}else{
		ClientPrint(null, 5, "ERROR: ENTITY 'rd_player_start' NOT FOUND")
	}
}
rd_damage_controll
 
//****************************************************************************************
//																						//
//									rd_damage_controll.nut								//
//																						//
//****************************************************************************************



// Fix grenade launcher applying damage to the player on multiple ticks 
// ----------------------------------------------------------------------------------------------------------------------------

lastDamageTimes <- {}

function AllowGrenadeLauncherDamage(player){
	
	if(!(player in lastDamageTimes)){
		lastDamageTimes[player] <- Time() - 1
	}
	
	if( Time() > lastDamageTimes[player] + 0.06 ){
			lastDamageTimes[player] <- Time()
			return true
	}else{
		lastDamageTimes[player] <- Time()
		return false
	}
}




// When to allow damage
// ----------------------------------------------------------------------------------------------------------------------------

function AllowTakeDamage(damageTable){
	local damageType = damageTable["DamageType"]
	local attacker = damageTable["Attacker"]
	local victim = damageTable["Victim"]
	local damageDone = damageTable["DamageDone"]
	
	// TANK ROCK
	if(damageTable.Victim.GetClassname() == "tank_rock"){
		if(attacker != null && attacker.IsPlayer() && attacker.GetZombieType() == 9){
			
			local victimScope = GetValidatedScriptScope(victim)

			if(!("dealtDamage" in victim.GetScriptScope())){
				victimScope["dealtDamage"] <- damageDone
			}else{
				victimScope["dealtDamage"] += damageDone
			}
			if(victimScope["dealtDamage"] >= 50){
				victimScope["dealtDamage"] <- -500
				if(attacker.IsIncapacitated()){
					if(!missionFailed){
						if(last_chance_active){
							stopLastChanceMode()
							attacker.ReviveFromIncap()
						}else{
							if(!allSurvivorsIncap()){
								attacker.ReviveFromIncap()
							}else{
								ClientPrint(null, 5, BLUE + "Time to say goodbye")
							}
						}
						EmitAmbientSoundOn("player/orch_hit_csharp_short", 1, 100, 100, attacker);	
					}
				}else{
					if((attacker.GetHealth() + 5) <= 200){
							attacker.SetHealth(attacker.GetHealth() + 5)
					}else{
						attacker.SetHealth(200)
					}
					attacker.UseAdrenaline(1)
				}
			}
		}
	return true
	}


	// DISABLE FALL DAMAGE
	if(damageType == 32){
		return false
	}
	
	// DISABLE FF
	if(attacker.IsPlayer()){
		if(victim.IsPlayer()){
			if(attacker.GetZombieType() == 9 && victim.GetZombieType() == 9){
				if(IsPlayerABot(attacker)){
					return false
				}
				
				if(damageTable.Weapon == null){
					if(!AllowGrenadeLauncherDamage(victim)){
						return false
					}else{
						damageTable.DamageDone = 1
						return true
					}
				}
			}
		}
	}
	return true
}
rd_debug
 
//****************************************************************************************
//																						//
//										rd_debug.nut									//
//																						//
//****************************************************************************************

// Check if dev mode is active
// ----------------------------------------------------------------------------------------------------------------------------

::DevModeActive <- function(){
	return Convars.GetFloat("developer")
}




// Switch from mushroom to mushroom
// ----------------------------------------------------------------------------------------------------------------------------

::debugMushroom <- null;

::GoToNextMushroom <- function(ent){
	if(!DevModeActive()){
		return
	}
	
	if(debugMushroom = Entities.FindByModel(debugMushroom, "models/props_collectables/mushrooms_glowing.mdl")){
		NetProps.SetPropInt(ent, "m_MoveType", 8)
		ent.SetOrigin(debugMushroom.GetOrigin() + Vector(0,0,64))
	}else{
		NetProps.SetPropInt(ent, "m_MoveType", 2)
	}
}
rd_decals
 
//****************************************************************************************
//																						//
//										rd_decals.nut									//
//																						//
//****************************************************************************************




// Will place decals depending on map
// ----------------------------------------------------------------------------------------------------------------------------

::placeRocketDudeDecals <- function(){
	local texture = "decals/rocketdude/rd_logo_glow"
	
	if(mapName in RocketDudeDecals){
		foreach(pos in RocketDudeDecals[mapName]){
			if(mapName == "c14m1_junkyard" || mapName == "c14m2_lighthouse"){
				texture = "decals/rocketdude/rd_logo_glow_big"
			}
			applyDecalAt(pos, texture)
		}
	}
}




// Applies a decal with texture X on position Y
// ----------------------------------------------------------------------------------------------------------------------------

::applyDecalAt <- function (pos, tex){
	local decal = SpawnEntityFromTable( "infodecal", { targetname = "rd_decal", texture = tex, LowPriority = 0, origin = pos } )
	DoEntFire( "!self", "Activate", "", 0.0, decal, decal )
}




// Decal data for maps c1 - c14
// ----------------------------------------------------------------------------------------------------------------------------

::RocketDudeDecals <-
{
	c1m1_hotel			= [ Vector(2064.64,6783.97,2882) ]
	c1m2_streets		= [ Vector(-1174.98,728.091,912.947) ]
	c1m3_mall			= [ Vector(1776.31,-2015.99,642.575) ]
	c1m4_atrium			= [ Vector(-3927.97,-3403.11,856.501) ]

	c2m1_highway		= [ Vector(1338.82,-1736.51,-1087.55) ]
	c2m2_fairgrounds	= [ Vector(-495.969,-1238.1,187.207) ]
	c2m3_coaster		= [ Vector(303.034,3328.03,349.983) ]
	c2m4_barns 			= [ Vector(3717.22,576.031,-127.915) ]
	c2m5_concert 		= [ Vector(-4368.03,2687,236.19) ]

	c3m1_plankcountry 	= [ Vector(-3712,4349.86,-74.6688) ]
	c3m2_swamp 			= [ Vector(-3923.97,4650.4,85.4511) ]
	c3m3_shantytown 	= [ Vector(-5602.41,-1635.03,258.268) ]
	c3m4_plantation 	= [ Vector(1853.52,76.6953,600.031) ]

	c4m1_milltown_a 	= [ Vector(1643.17,4338.16,433.805) ]
	c4m2_sugarmill_a 	= [ Vector(2966.24,-3271.43,1200.15) ]
	c4m3_sugarmill_b 	= [ Vector(1424.04,-6088.03,416.549) ]
	c4m4_milltown_b 	= [ Vector(1437.01,6364.88,334.595) ]
	c4m5_milltown_escape = [ Vector(-5874.37,8072.03,377.766) ]

	c5m1_waterfront		= [ Vector(-2144.03,-2508.57,-334.026) ]
	c5m2_park			= [ Vector(-10102.6,-5538.72,48.0313) ]
	c5m3_cemetery		= [ Vector(3511.2,3503.97,258.566) ]
	c5m4_quarter		= [ Vector(-2060.97,3392.03,132.305) ]
	c5m5_bridge			= [ Vector(14288.3,6326.82,790.031) ]

	c6m1_riverbank		= [ Vector(1301.35,1616.03,578.07) ]
	c6m2_bedlam			= [ Vector(3964.55,4096.03,-549.714) ]
	c6m3_port			= [ Vector(-1258.88,-307.692,480.031) ]

	c7m1_docks			= [ Vector(2835.56,901.987,448.031) ]
	c7m2_barge 			= [ Vector(-10349.8,415.969,341.246) ]
	c7m3_port 			= [ Vector(-2223.97,-537.898,-32.6826) ]

	c8m1_apartment 		= [ Vector(1710.64,4568.03,264.95) ]
	c8m2_subway 		= [ Vector(9519.12,3772.03,71.1739) ]
	c8m3_sewers 		= [ Vector(15280,15322.9,72.8583) ]
	c8m4_interior 		= [ Vector(13064,14173,632.224) ]
	c8m5_rooftop		= [ Vector(7291.74,8976.03,470.528) ]

	c9m1_alleys			= [ Vector(1466.98,-1663.97,-161.193) ]
	c9m2_lots			= [ Vector(4135.19,1263.97,252.13) ]

	c10m1_caves			= [ Vector(-12608,-9505.11,27.5156) ]
	c10m2_drainage		= [ Vector(-9007.97,-9040.36,-377.031) ]
	c10m3_ranchhouse	= [ Vector(-9690.9,-7808.03,545.451) ]
	c10m4_mainstreet	= [ Vector(-1181.2,-4732.03,253.471) ]
	c10m5_houseboat		= [ Vector(2239.22,4086.55,72.0313) ]

	c11m1_greenhouse	= [ Vector(3248.03,961.976,69.2323) ]
	c11m2_offices		= [ Vector(5168.03,137.882,69.3103) ]
	c11m3_garage		= [ Vector(-2448.03,1375.55,217.825) ]
	c11m4_terminal		= [ Vector(1992.03,3128.09,513.913) ]
	c11m5_runway		= [ Vector(-7215.97,14444.1,623.558) ]

	c12m1_hilltop		= [ Vector(-7670.79,-7375.85,1478.86) ] 
	c12m2_traintunnel	= [ Vector(-7996.38,-7685.76,1329.54) ] 
	c12m3_bridge		= [ Vector(1828.55,-12166.7,484.031) ]
	c12m4_barn			= [ Vector(9825.65,-6235.72,861.689) ] 
	c12m5_cornfield		= [ Vector(4736,1515.6,362.583) ]

	c13m1_alpinecreek	= [ Vector(-3956.75,3989.21,461.736) ]
	c13m2_southpinestream = [ Vector(1329.92,993.69,170.069) ]
	c13m3_memorialbridge = [ Vector(6804.03,-4099.88,1720.87) ] 
	c13m4_cutthroatcreek = [ Vector(-731.623,1533.44,-48.6967) ] 

	c14m1_junkyard 		= [ Vector(-3616.64,-9215.38,165.2) ]
	c14m2_lighthouse	= [ Vector(340.733,-240.909,394.865) ] 

}
rd_detonation_analysis
 
//****************************************************************************************
//																						//
//								rd_detonation_analysis.nut								//
//																						//
//****************************************************************************************




// Distance between player eyepos and wall < distance between player eyepos to floor/ceiling...
// Thats why we want to have a higher value when the hit surface was a wall.
// ----------------------------------------------------------------------------------------------------------------------------

function getSurfaceValue(detonationPos,player){
	
	local traceTableX1 = { start = detonationPos+Vector(2,0,0), end = detonationPos+Vector(-2,0,0), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }
	local traceTableX2 = { start = detonationPos+Vector(-2,0,0), end = detonationPos+Vector(2,0,0), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }

	local traceTableY1 = { start = detonationPos+Vector(0,2,0), end = detonationPos+Vector(0,-2,0), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }
	local traceTableY2 = { start = detonationPos+Vector(0,-2,0), end = detonationPos+Vector(0,2,0), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }

	local traceTableZ1 = { start = detonationPos+Vector(0,0,2), end = detonationPos+Vector(0,0,-2), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }
	local traceTableZ2 = { start = detonationPos+Vector(0,0,-2), end = detonationPos+Vector(0,0,2), ignore = player, mask = TRACE_MASK_PLAYER_SOLID }

	TraceLine(traceTableX1)
	TraceLine(traceTableX2)
	TraceLine(traceTableY1)
	TraceLine(traceTableY2)
	TraceLine(traceTableZ1)
	TraceLine(traceTableZ2)

	// WALL
	if("hit" in traceTableX1 && traceTableX1.hit == true ||  "hit" in traceTableX2 && traceTableX2.hit == true ){
		return "WALL"
	}
	// WALL
	else if("hit" in traceTableY1 && traceTableY1.hit == true ||  "hit" in traceTableY2 && traceTableY2.hit == true ){
		return "WALL"
	}
	// CEILING/FLOOR
	else if("hit" in traceTableZ1 && traceTableZ1.hit == true ||  "hit" in traceTableZ2 && traceTableZ2.hit == true ){
		return "CLOOR"
	}else{
		return "WALL" // Just in case...
	}
}
rd_director
 
//****************************************************************************************
//																						//
//										rd_director.nut									//
//																						//
//****************************************************************************************




MutationOptions <-
{
	// General
	cm_NoSurvivorBots	= 1
	
	// Special Infected
	MaxSpecials			= 6

	// Convert items
	weaponsToConvert =
	{
		weapon_first_aid_kit =	"weapon_pain_pills_spawn"
	}

	function ConvertWeaponSpawn(classname){
		if (classname in weaponsToConvert){
			return weaponsToConvert[classname]
		}
		return 0
	}	
	
	
	// Controll which weapons are allowed to be spawned
	weaponsToPreserve =
	{
		weapon_pain_pills		= 0
		weapon_adrenaline		= 0
		weapon_melee			= 0
		weapon_first_aid_kit	= 0
		weapon_gascan			= 0
		weapon_pistol_magnum	= 0
		weapon_grenade_launcher = 0
	}

	function AllowWeaponSpawn(classname){
		if(!IsValveMap()){
			if(classname in weaponsToPreserve){
				return true;
			}
		}
		
		if (classname in weaponsToPreserve){
			return true;
		}
		return false;
	}
	
	// Avoid fallen survivors carrying items
	function AllowFallenSurvivorItem(item){
		return false
	}
	
	// Get default items for survivors
	DefaultItems =
	[
		"weapon_grenade_launcher",
		RandomInt(0, 1) ? getAvailableMelee("Sharp") : "weapon_pistol_magnum"
	]

	function GetDefaultItem( idx ){
		if ( idx < DefaultItems.len() ){
			return DefaultItems[idx]
		}
		return 0
	}
}
rd_events
 
//****************************************************************************************
//																						//
//										rd_events.nut									//
//																						//
//****************************************************************************************




::devs <- {}
	
devs["STEAM_1:0:26359107"] <- { name = "ReneTM", role = "creator" }
devs["STEAM_1:0:16327272"] <- { name = "Derdoron", role = "Beta Tester" }




// Chat commands
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_player_say(params){

	local text,ent = null
	
	if("userid" in params && params.userid == 0){
		return
	}
	
	text = strip(params["text"].tolower())
	ent = GetPlayerFromUserID(params["userid"])

	if(text.len() < 1){
		return
	}
	
	local steamID = ent.GetNetworkIDString()
	local scope = GetValidatedScriptScope(ent)

	switch(text){

		case "!version" :
		if(steamID in devs){
			ClientPrint(null, 5, BLUE + "RocketDude " + rocketdude_version)
		}
		break
		
		case "!countdown" :
		startSafeRoomTimer(ent)
		break
		
		case "!r" :
		restartFromSaferoom(ent)
		break
		
		case "!saveangles" :
		savePlayerEyeAngles(ent)
		break
		
		case "!speedrunmode" :
		speedrunModeToggle(ent)
		break
		
		case "!hud" :
		ChangeHudState(ent)
		break
		
		case "!stats" :
		outputStats(ent)
		break
		
		case "!info" :
		printMutationInfo(ent)
		break
		
		case "!g2mushroom" :
		GoToNextMushroom(ent)
		break
	}
}




function OnGameEvent_player_first_spawn(params){
	
	local orangestar = ORANGE + "★"

	if(params["isbot"] == 0){
		local player = GetPlayerFromUserID(params.userid)
		local steamID = player.GetNetworkIDString()

		if(steamID in devs){
			local invTable = {}
			GetInvTable(player, invTable)
			if("slot1" in invTable && invTable.slot1.GetClassname() == "weapon_melee"){
				if(NetProps.GetPropString(invTable.slot1, "m_strMapSetScriptName") != "crowbar"){
					invTable.slot1.Kill()
					player.GiveItemWithSkin("crowbar", 1)
				}else{
					NetProps.SetPropInt(invTable.slot1, "m_nSkin", 1)
				}
			}
			ClientPrint(null, 5, orangestar + GREEN + " RocketDude " + devs[steamID].role + BLUE + " " + player.GetPlayerName() + WHITE + " joined the game.")
		}
	}
}




// "The right man in the wrong place can make all the difference in the world"
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_player_changename(params){
	local player = GetPlayerFromUserID(params["userid"])
	local invTable = {}
	GetInvTable(player, invTable)
	
	if("newname" in params && params["newname"] == "Dr. Gordon Freeman"){
		if("slot1" in invTable && invTable.slot1.GetClassname() == "weapon_melee"){
			if(NetProps.GetPropString(invTable.slot1, "m_strMapSetScriptName") == "crowbar"){
				NetProps.SetPropInt(invTable.slot1, "m_nSkin", 1)
			}
		}
	}
}




function OnGameEvent_player_spawn(params){

	local player = GetPlayerFromUserID(params["userid"])
	
	if(player.GetZombieType() == 9 && !IsPlayerABot(player)){
		placeRocketDudeDecals()
		teleportToSurvivor(player)
		
		DoEntFire("!self", "DisableLedgeHang", "", 0.0, player, player)
		DoEntFire("!self", "ignorefalldamagewithoutreset", "99999", 0.0, player, player)

		if(NetProps.GetPropInt(player, "m_iMaxHealth") != 200){
			NetProps.SetPropInt(player, "m_iMaxHealth", 200)
		}
	}
}




function teleportToSurvivor(player){
	local target = getClosestSurvivorTo(player)
	
	if(target == null){
		return
	}
	
	if((player.GetOrigin() - target.GetOrigin()).Length() < 256){
		return
	}
	
	if(target.IsValid()){
		if(!target.IsDead() && !target.IsDying()){
			if(Director.HasAnySurvivorLeftSafeArea()){
				player.SetOrigin(target.GetOrigin())
			}
		}
	}
}




function OnGameEvent_player_incapacitated(params){
	
	if("attackerentid" in params){
		if(EntIndexToHScript(params.attackerentid).GetClassname() == "trigger_hurt"){
			return
		}
	}

	if(!lastChanceUsed){
		lastChanceSwitch(params)
	}
}




// When a survivor stands full hp in a mushroom trigger volume the function is unlocked
// again and the survivor gets hurt a touchtest should be done
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_player_hurt(params){
	if(GetPlayerFromUserID(params.userid).GetZombieType() == 9){
		foreach(trigger in medkit_triggers){
			DoEntFire("!self", "TouchTest", "", 0, trigger, trigger)
		}
	}
}




// Disable glows when survivors enter "last chance mode" but fail
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_mission_lost(params){
	disableInfectedGlows()
}




// Called when any player dies. Purpose mostly for bullet time, reviving survivors from being incap and "last chance"
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_player_death(params){
	
	local victim = null
	local attacker = null
	local victimClass = null
	
	if("userid" in params){
		victim = GetPlayerFromUserID(params["userid"])
	} else if("entityid" in params){
		victim = EntIndexToHScript(params["entityid"])
	}
	if("attacker" in params){
		attacker = GetPlayerFromUserID(params["attacker"])
	} else if("attackerentid" in params){
		attacker = EntIndexToHScript(params["attackerentid"])
	}
	
	if(!lastChanceUsed){
		lastChanceSwitch(params)	
	}
	
	if(victim.IsPlayer() && victim.GetZombieType() == 9){
		ClientPrint(null, 5, BLUE + victim.GetPlayerName() + WHITE + " did not finish this map. The map finished them.")
	}
	

	if(victim.GetClassname() != "infected"){
		if(victim.GetClassname() == "witch" || victim.GetZombieType() != 9){	// Killed witch or any Special infected or tank
			if(attacker != null && attacker.IsPlayer()){						// Dont do anything when the map is the killer
				if(attacker.GetZombieType() == 9){
					if(attacker.IsIncapacitated()){
						if(!missionFailed){
							if(last_chance_active){
								stopLastChanceMode()
								attacker.ReviveFromIncap()
							}else{
								if(!allSurvivorsIncap()){
									attacker.ReviveFromIncap()
								}else{
									ClientPrint(null, 5, BLUE + "Time to say goodbye")
								}
							}
							EmitAmbientSoundOn("player/orch_hit_csharp_short", 1, 100, 100, attacker)
						}
					}
				}
			}
		}
	}else{
		if(attacker != null && attacker.GetClassname() == "player" && attacker.GetZombieType() == 9){
			bulletTime()
		}
	}
}




// Set tank's health in relation to the current difficulty
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_tank_spawn(params){
	local tank = EntIndexToHScript(params.tankid)
	local health = 0
	switch(Convars.GetStr("z_difficulty").tolower()){
		case "easy" :
			health = 8000;	break
		case "normal" :
			health = 16000;	break
		case "hard" :
			health = 32000;	break
		case "impossible" :
			health = 64000;	break
	}
	tank.SetMaxHealth(health)
	tank.SetHealth(health)
}




// Set witch health in relation to the current difficulty
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_witch_spawn(params){
	local witch = EntIndexToHScript(params.witchid)
	local health = 0
	
	switch(Convars.GetStr("z_difficulty").tolower()){
		case "easy" :
			health = 2048;	break
		case "normal" :
			health = 4096;	break
		case "hard" :
			health = 8192;	break
		case "impossible" :
			health = 16384; break
	}
	witch.SetMaxHealth(health)
	witch.SetHealth(health)
}




// Avoid multiple rocketlaunchers on the ground 
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_item_pickup(params){
	local player = GetPlayerFromUserID(params["userid"])
	local playerInv = {}
	if(player.GetZombieType() == 9 && !IsPlayerABot(player)){
		GetInvTable(player, playerInv)
		if("slot0" in playerInv){
			if(playerInv["slot0"].GetClassname() != "weapon_grenade_launcher"){
				playerInv["slot0"].Kill()
				player.GiveItem("weapon_grenade_launcher")
			}
		}
		
		// Gives devs a golden crowbar
		if(player.GetNetworkIDString() in devs){
			if("slot1" in playerInv){
				if(NetProps.GetPropString(playerInv.slot1, "m_strMapSetScriptName") == "crowbar"){
					NetProps.SetPropInt(playerInv.slot1, "m_nSkin", 1)
				}
			}
		}
	}
}




function OnGameEvent_weapon_drop(params){
	if("propid" in params){
		local droppedItem = EntIndexToHScript(params.propid)
		if(droppedItem.GetClassname() == "weapon_grenade_launcher"){
			droppedItem.Kill()
		}
	}
}

::entityChangesDone <- false

function OnGameEvent_player_left_checkpoint(params){
	if("userid" in params){
		local player = GetPlayerFromUserID(params["userid"])
		if(player.GetZombieType() == 9 && !IsPlayerABot(player) && !player.IsDead()){
			if(player in PlayerTimeData){
				if(!PlayerTimeData[player].finished){
					PlayerTimeData[player].timerActive = true
					PlayerTimeData[player].startTime = Time()
					PlayerTimeData[player].seconds = 0
					PlayerTimeData[player].ticks = 0
					EmitAmbientSoundOn("ui/beep07.wav", 0.5, 100, 107, player)
					ClientPrint(player, 5, BLUE + player.GetPlayerName() + " | 00:00")
				}
			}
		
			if(!IsPlayerABot(player)){
				if(!entityChangesDone){
					DoEntFire("worldspawn", "RunScriptCode", "killFixEntities()", 2, player, player)
					DoEntFire("worldspawn", "RunScriptCode", "mapSpecifics()", 4, player, player)
					entityChangesDone = true
				}
			}

			DoEntFire("!self", "DisableLedgeHang", "", 0.0, player, player)
			DoEntFire("!self", "ignorefalldamagewithoutreset", "99999", 0.0, player, player)

			if(NetProps.GetPropInt(player, "m_iMaxHealth") != 200){
				NetProps.SetPropInt(player, "m_iMaxHealth", 200)
			}
		}
	}
}




// Like in Portal 1 we want to challange the player to do as less steps as possible or atleast to spend as less time on the 
// ground as possible. Event "player_footstep" is non-functional atm...Valve please fix
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_finale_vehicle_leaving(param){
	finalGroundTimeOutput()
}




function OnGameEvent_finale_win(param){
	finalGroundTimeOutput()
}




function finalGroundTimeOutput(){
	foreach(player,datatable in PlayerTimeData){
		if(player.IsValid()){
			if(!player.IsDead() && !player.IsDying() && !player.IsIncapacitated()){
				if(!PlayerTimeData[player].finished){
					printFinalGroundTime(player)
					ProcessSurvivorTime(player)
				}
			}
		}
	}
}




function ProcessSurvivorTime(ent){
	
	local tTable = PlayerTimeData[ent]
	tTable.endTime = Time()
	
	if(tTable.time_best == 0){
		tTable.time_best = tTable.endTime - tTable.startTime
	}else{
		if((tTable.endTime - tTable.startTime) < tTable.time_best){
			tTable.time_best = (tTable.endTime - tTable.startTime)
		}
	}
	tTable.finished = true
}




::printFinalGroundTime <- function(ent){
	if(!ent.IsDead() && !ent.IsDying() && !ent.IsIncapacitated()){
		local sec = PlayerTimeData[ent].seconds
		local fracs = PlayerTimeData[ent].ticks.tofloat()
		if(fracs > 0){
			fracs = (fracs / 30)
		}
		local groundTime = sec + fracs
		local time_curr = limitDecimalPlaces( Time() - (PlayerTimeData[ent].startTime).tofloat() )
		local midAirPercent = getMidAirPercentage(groundTime, time_curr)
		
		ClientPrint(null, 5, BLUE + ent.GetPlayerName() + WHITE + " finished this map in " + BLUE + time_curr + WHITE + " seconds and spent " + BLUE + midAirPercent + WHITE + " % midair")
		EmitAmbientSoundOn("ui/menu_invalid.wav", 0.75, 100, 110, ent)
		
		local diff = GetSpeedrunStats(ent, time_curr)

		// Speedrun tracker
		
		if( diff != null ){
			if( diff < 0){
				ClientPrint(null, 5, WHITE + "Thats a new personal record for " + mapName + GREEN + " ( "  + diff.tostring() + " seconds )")
				return
			}else if(diff > 0){
				ClientPrint(null, 5, ORANGE + "( +" + ( diff.tostring()) + " seconds )" )
				return
			}
		}
	}
}




::getMidAirPercentage <- function(groundTime, time_curr){
	local airTime = time_curr - groundTime
	local airPercentage = (( airTime / time_curr ) * 100).tofloat()
	return limitDecimalPlaces(airPercentage)
}




::limitDecimalPlaces <- function(var){
	return (var * 100).tointeger() / 100.0
}




// Check if the text from the file is a "number"
// ----------------------------------------------------------------------------------------------------------------------------

::isNumeric <- function(value){
	local newValue
	local dots = 0
	local numbers = ["0","1","2","3","4","5","6","7","8","9","."]
	for(local i=0; i < value.len(); i++){
		local checkChar = value.slice(i, i+1)
		if(checkChar == "."){
			dots++
		}
		if(dots > 1){
			return false
		}
		if(numbers.find(checkChar) == null){
			return false
		}
	}
	return true
}




// Record output for the local player
// ----------------------------------------------------------------------------------------------------------------------------

::GetSpeedrunStats <- function(player, newTime){
	
	// Restrict saving for the local player
	if(!(player == GetListenServerHost())){
		return null
	}
	
	local filePath = "rocketdude/speedrun/"
	local fileName = mapName + ".txt"
	
	local savedTime = FileToString(filePath + fileName)
	
	// Save a file when there is none
	if(savedTime == null || savedTime.len() == 0 || !isNumeric(savedTime)){
		StringToFile(filePath + fileName, newTime.tostring() )
		return null
	}
	
	try{
		savedTime = savedTime.tofloat()
	}catch(exception){
		return null
	}
	
	if(newTime < savedTime){
		StringToFile(filePath + fileName, newTime.tostring() )
	}
	
	return (newTime - savedTime)
}




// Typing sv_cheats 1 on local server would result in every cheat flagged variable reset
// ----------------------------------------------------------------------------------------------------------------------------

function OnGameEvent_server_cvar(param){
	if("cvarname" in param){
		local cvar = param.cvarname
		if(cvar == "sv_cheats"){
			checkCvars()
		}
	}
}




__CollectEventCallbacks(this, "OnGameEvent_", "GameEventCallbacks", RegisterScriptGameEventListener)
rd_hud_controller
 
//****************************************************************************************
//																						//
//									rd_hud_controller.nut								//
//																						//
//****************************************************************************************




// Flag and position tables
// ----------------------------------------------------------------------------------------------------------------------------

::HUDFlags <- {
	PRESTR = 1
	POSTSTR = 2
	BEEP = 4
	BLINK = 8
	AS_TIME = 16
	COUNTDOWN_WARN = 32
	NOBG = 64
	ALLOWNEGTIMER = 128
	ALIGN_LEFT = 256
	ALIGN_CENTER = 512
	ALIGN_RIGHT = 768
	TEAM_SURVIVORS = 1024
	TEAM_INFECTED = 2048
	TEAM_MASK = 3072
	NOTVISIBLE = 16384
}

::HUDPositions <- {
	LEFT_TOP = 0
	LEFT_BOT = 1
	MID_TOP = 2
	MID_BOT = 3
	RIGHT_TOP = 4
	RIGHT_BOT = 5
	TICKER = 6
	FAR_LEFT = 7
	FAR_RIGHT = 8
	MID_BOX = 9
	SCORE_TITLE = 10
	SCORE_1 = 11
	SCORE_2 = 12
	SCORE_3 = 13
	SCORE_4 = 14
}




// Main hud definition
// ----------------------------------------------------------------------------------------------------------------------------

RD_HUD <-
{
	Fields = 
	{
		timer = { slot = HUDPositions.MID_BOX, flags = HUDFlags.ALIGN_CENTER | HUDFlags.NOBG, name = "timer", datafunc = @()GetPlayerTimes() }
	}
}




// Returns one string for all survivors
// ----------------------------------------------------------------------------------------------------------------------------

::GetPlayerTimes <- function(){
	local str = ""
	
	foreach(ent in GetHumanSurvivors()){
		str += (GetCharacterDisplayName(ent) + ": ")
		if(ent in PlayerTimeData){
			if(!ent.IsDead() && !ent.IsDying()){
				if(PlayerTimeData[ent].timerActive){
					if(!PlayerTimeData[ent].finished){
						str += g_MapScript.TimeToDisplayString(Time() - PlayerTimeData[ent].startTime)
					}else{
						str += "Finished(" + g_MapScript.TimeToDisplayString(PlayerTimeData[ent].endTime - PlayerTimeData[ent].startTime) + ")"
					}
				}else{
					str += "0:00" 
				}
			}else{
				str += "(Dead)"
			}
		}
		str += "  "
	}
	return str
}




// Voting to disable the timer hud
// ----------------------------------------------------------------------------------------------------------------------------

function ChangeHudState(ent){
	local scope = GetValidatedScriptScope(ent)
	scope["speedrun_timer"] <- true
	
	foreach(player in GetHumanSurvivors()){
		local playerscope = GetValidatedScriptScope(player)
		if(!("speedrun_timer" in playerscope)){
			ClientPrint(null, 5, GREEN + ent.GetPlayerName() + WHITE + " voted to " + ( IsTimerHudActive() ? "disable" : "enable" ) + " the timer hud")
			return
		}
	}
	
	if(IsTimerHudActive()){
		DisableTimerHud()
	}else{
		EnableTimerHud()
	}
	
	foreach(player in GetHumanSurvivors()){
		local scope = GetValidatedScriptScope(player)
		if("speedrun_timer" in scope){
			player.GetScriptScope().rawdelete("speedrun_timer")
		}
	}
	
	ClientPrint(null, 5, WHITE + "Hud has been " + GREEN + ( IsTimerHudActive() ? "enabled" : "disabled") )
}




// Enable / disable the hud
// ----------------------------------------------------------------------------------------------------------------------------

function EnableTimerHud(){
	RD_HUD.Fields.timer.flags <- RD_HUD.Fields.timer.flags & ~HUDFlags.NOTVISIBLE
	HUDPlace(HUDPositions.MID_BOX, 0.0, 0.0, 1.0, 0.05)
}




function EnableTickerHud(){
	Ticker_AddToHud(RD_HUD, "!info in chat to print mutation details to your console", true)
	HUDPlace(HUDPositions.TICKER, 0.0, 0.0, 0.99, 0.25)
	Ticker_SetTimeout(16)
	Ticker_SetBlinkTime(16)
	RD_HUD.Fields.ticker.flags <- HUDFlags.ALIGN_CENTER | HUDFlags.NOBG | HUDFlags.BLINK
}




function DisableTimerHud(){
	RD_HUD.Fields.timer.flags <- RD_HUD.Fields.timer.flags | HUDFlags.NOTVISIBLE
}




// Checks if the timer hud is currently visible
// ----------------------------------------------------------------------------------------------------------------------------

function IsTimerHudActive(){
	return !(RD_HUD.Fields.timer.flags & HUDFlags.NOTVISIBLE)
}


EnableTimerHud()

EnableTickerHud()

HUDSetLayout(RD_HUD)
rd_last_chance
 
//****************************************************************************************
//																						//
//									rd_last_chance.nut									//
//																						//
//****************************************************************************************




// Basic functions to check if survivors are dead / capped
// ----------------------------------------------------------------------------------------------------------------------------

function allSurvivorsIncap(){
	foreach(survivor in GetSurvivors()){
		//if(!survivor.IsIncapacitated() && !survivor.IsHangingFromLedge() && !survivor.IsDead() && !survivor.IsDying() && !playerIsCapped(survivor)){  // 20200913
		if(!survivor.IsIncapacitated() && !survivor.IsDead() && !survivor.IsDying()){
			return false
		}
	}
	return true
}

function allSurvivorsDead(){
	foreach(survivor in GetSurvivors()){
		if(!survivor.IsDead() && !survivor.IsHangingFromLedge()){
			return false
		}
	}
	return true
}

function playerIsCapped(player){
	local infected = null;
	local keys = ["m_pummelVictim","m_carryVictim","m_pounceVictim","m_jockeyVictim","m_tongueVictim"]
	while(infected = Entities.FindByClassname(infected, "player")){
		if(infected.GetZombieType() != 9){
			foreach(key in keys){
				if(NetProps.GetPropEntity(infected, key) == player){
					return true
				}
			}
		}
	}
	return false
}




// When all survivors are incapacitated, give them 10 seconds to kill any special infected or boss infected ( BL-Style )
// ----------------------------------------------------------------------------------------------------------------------------

::last_chance_active	<- false
lastChanceCheckStamp	<- Time()
remainingReviveTime		<- 10
::missionFailed			<- false
::lastChanceUsed		<- false



// Called on player_death and player_incapacitated it will call enableLastChanceVision()
// when all survivors are incap but not all are dead
// ----------------------------------------------------------------------------------------------------------------------------

function lastChanceSwitch(params){
	if(!allSurvivorsDead()){
		if("userid" in params && GetPlayerFromUserID(params.userid).GetZombieType() == 9){
			if(allSurvivorsIncap() && !last_chance_active){
				enableLastChanceVision();
				lastChanceUsed = true
				last_chance_active = true
				remainingReviveTime = 10
				Convars.SetValue("director_no_death_check", 1)
				lastChanceCheckStamp = Time()
			}
		}
	}
}




// Called every tick, it will outout a countdown to timeout the survivors
// ----------------------------------------------------------------------------------------------------------------------------

function lastChanceCountDown(){
	if(last_chance_active){
		if(Time() >= lastChanceCheckStamp + 1 ){
			lastChanceCheckStamp = Time()
			if(allSurvivorsIncap()){
				if(remainingReviveTime == 0){
					last_chance_active = false
					Convars.SetValue("director_no_death_check", 0)
					ClientPrint(null, 5, BLUE + "Sorry, you don't have any time left to repopulate the world.")
					missionFailed = true
				}else{
					ClientPrint(null, 5, BLUE + remainingReviveTime)
				}
				remainingReviveTime --
			}else{
				last_chance_active = false
				Convars.SetValue("director_no_death_check", 0)
			}
		}
	}
}




// Will switch survivors vision to "black and white" and enables outline glows for special and boss infected
// ----------------------------------------------------------------------------------------------------------------------------

function enableLastChanceVision(){
	whiteScreen();
	local player = null
	local witch = null
	local rock = null
	
	while(player = Entities.FindByClassname(player, "player")){
		if(player.GetZombieType() != 9 && !player.IsDead() && !player.IsDying()){
			NetProps.SetPropInt(player, "m_Glow.m_iGlowType", 3)
			setInfectedGlowColor(player)
		}
		if(player.GetZombieType() == 9){
			player.SetReviveCount(2)
		}
	}
	while(witch = Entities.FindByClassname(witch, "witch")){
		if(witch.IsValid()){
			NetProps.SetPropInt(witch, "m_Glow.m_iGlowType", 3)
			setInfectedGlowColor(witch)
		}
	}
	while(rock = Entities.FindByClassname(rock, "tank_rock")){
		if(rock.IsValid()){
			NetProps.SetPropInt(rock, "m_Glow.m_iGlowType", 3)
			setInfectedGlowColor(rock)
		}
	}
}




// After a survivor gets a kill on any special or boss infected this should get called also
// ----------------------------------------------------------------------------------------------------------------------------

function stopLastChanceMode(){
	local player = null;
	local witch = null;
	local rock = null;
	while(player = Entities.FindByClassname(player, "player")){
		NetProps.SetPropInt(player, "m_Glow.m_iGlowType", 0)
		if(player.GetZombieType() == 9){
			player.SetReviveCount(1)
		}
	}
	while(witch = Entities.FindByClassname(witch, "witch")){
		NetProps.SetPropInt(witch, "m_Glow.m_iGlowType", 0)
	}
	while(rock = Entities.FindByClassname(rock, "tank_rock")){
		if(rock.IsValid()){
			NetProps.SetPropInt(rock, "m_Glow.m_iGlowType", 0)
		}
	}
}




// Called on mission_fail it will disable all infected glows of "last chance"
// ----------------------------------------------------------------------------------------------------------------------------

function disableInfectedGlows(){
	local player = null;
	local witch = null;
	while(player = Entities.FindByClassname(player, "player")){
		NetProps.SetPropInt(player, "m_Glow.m_iGlowType", 0)
	}
	while(witch = Entities.FindByClassname(witch, "witch")){
		NetProps.SetPropInt(witch, "m_Glow.m_iGlowType", 0)
	}
}




// Fade effect for entering the last chance vision
// ----------------------------------------------------------------------------------------------------------------------------

function whiteScreen(){
	foreach(player in GetHumanSurvivors()){
		ScreenFade(player, 200, 200, 200, 255, 1, 0.5, 1)
	}
}




// Change infected glows in "last_chance_mode" depending on difficulty
// ----------------------------------------------------------------------------------------------------------------------------

function setInfectedGlowColor(inf){
	local vector = null;
	switch(Convars.GetStr("z_difficulty").tolower()){
		case "easy"			: vector = Vector(255,45,180);	break;
		case "normal"		: vector = Vector(0,255,0);		break;
		case "hard"			: vector = Vector(200,0,0);		break;
		case "impossible"	: vector = Vector(120,120,120);	break;
		default				: vector = Vector(165,0,255);	break;
	}
	local color = vector.x
	color += 256 * vector.y
	color += 65536 * vector.z
	NetProps.SetPropInt(inf, "m_Glow.m_glowColorOverride", color)
}




// Returns vector color as int
// ----------------------------------------------------------------------------------------------------------------------------

function GetColorInt(col){
	
	if(typeof(col) == "Vector"){
		local color = col.x
		color += 256 * col.y
		color += 65536 * col.z
		return color
	}else if(typeof(col) == "string"){
		local colorArray = split(col, " ")
		local r = colorArray[0].tointeger()
		local g = colorArray[1].tointeger()
		local b = colorArray[2].tointeger()
		local color = r
		color += 256 * g
		color += 65536 * b
		return color
	}
}
rd_map_specifics
 
//****************************************************************************************
//																						//
//									rd_map_specifics.nut								//
//																						//
//****************************************************************************************




// Some maps require minor adjustments to improve gameplay. 
// ----------------------------------------------------------------------------------------------------------------------------

::mapSpecifics <- function(){
	switch(mapName){
		case "c1m1_hotel"				:	rd_specifics_c1m1();	break
		case "c1m2_streets"				:	rd_specifics_c1m2();	break
		case "c1m3_mall"				:	rd_specifics_c1m3();	break
		case "c5m5_bridge"				:	rd_specifics_c5m5();	break
		case "c7m3_port"				: 	rd_specifics_c7m3();	break
		case "c8m4_interior"			:	rd_specifics_c8m4();	break
		case "c8m5_rooftop"				:	rd_specifics_c8m5();	break
		case "c13m4_cutthroatcreek"		:	rd_specifics_c13m4();	break
		case "c14m1_junkyard"			:	rd_specifics_c14m1();	break
		case "c14m2_lighthouse"			:	rd_specifics_c14m2();	break
		default							:							break
	}
}




// Since we dont have any fall damage at all we should not stop players from just dropping down the hotel
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c1m1 <- function(){
	local deathTriggers =
	[
		Vector(3200.000,5312.000,1648.000),
		Vector(2944.000,5888.000,1648.000),
		Vector(2936.000,6932.000,1648.000),
		Vector(1516.800,8000.000,1520.000),
		Vector(632.000,6944.000,1648.000),
		Vector(1600.000,4608.000,1648.000),
		Vector(0.000,5632.000,1648.000)
	]
	foreach(triggerPos in deathTriggers){
		local ent = null
		if(ent = Entities.FindByClassnameNearest( "trigger_hurt", triggerPos, 4 )){
			ent.Kill()
		}
	}
}




// Force start of parish finale
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c5m5 <- function (){
	local ent = null
	if(ent = Entities.FindByClassname(null, "player")){
		DoEntFire( "radio_fake_button", "use", "", 1, ent, ent)
		DoEntFire( "finale", "use", "", 8, ent, ent)
		DoEntFire( "relay_init_heli", "Trigger", "", 12, ent, ent)
		DoEntFire( "relay_start_heli", "Trigger", "", 16, ent, ent)
	}
}




// Remove liftshaft_portal3_brush and rooftop_opening_clip
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c8m5 <- function(){
	local ent = null
	if(ent = Entities.FindByClassnameNearest( "func_brush", Vector(7248.000000, 9168.000000, 7144.000000), 4)){
		ent.Kill()
	}
}




// Force start of cold stream finale
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c13m4 <- function (){
	local ent = null
	if(ent = Entities.FindByClassname(null, "player")){
		DoEntFire( "startbldg_door_button", "use", "", 1, ent, ent)
		DoEntFire( "finale", "use", "", 12, ent, ent)
	}
}




// Change damage type of trigger_hurt ( water area in front of the end saferoom )
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c14m1 <- function(){
	local ent = null
	if(ent = Entities.FindByClassnameNearest( "trigger_hurt_ghost", Vector(-4580,9352,-732), 4)){
		TriggerSetDamageType(ent, damageTypes.GENERIC)
	}
}




// Kill trigger which re-enables the ledgehang
// Change damage type of trigger_hurt ( water of rescue vehicle zone )
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c14m2 <- function(){
	local ent = null
	
	if(ent = Entities.FindByClassnameNearest( "trigger_multiple", Vector(-4352,3928,1096), 4)){
		ent.Kill()
	}
	if(ent = Entities.FindByClassnameNearest( "trigger_hurt", Vector(-4608,7168,-256), 4)){
		TriggerSetDamageType(ent, damageTypes.GENERIC)
	}
	if(ent = Entities.FindByClassnameNearest("func_brush", Vector(275.000000, 930.000000, 1360.000000), 4)){
		ent.Kill()
	}
}




// Re-execute the elevator fix once
// ----------------------------------------------------------------------------------------------------------------------------


::rd_specifics_c8m4 <- function(){
	EntFire( "worldspawn", "RunScriptFile", "c8m4_elevatorfix" )
}




// Utils to manipulate entities
// ----------------------------------------------------------------------------------------------------------------------------

::TriggerSetDamageType <- function(ent, type){
	if(ent.GetClassname() == "trigger_hurt" || ent.GetClassname() == "trigger_hurt_ghost"){
		NetProps.SetPropInt(ent, "m_bitsDamageInflict", type)
	}
}




// Lets make c7m3 playable alone
// ----------------------------------------------------------------------------------------------------------------------------

::KillOldFinaleButton <- function(){
	local triggerFinale = null
		if(triggerFinale = Entities.FindByClassname(triggerFinale, "trigger_finale")){
			triggerFinale.Kill()
		}
	
	local br = null
	if(br = Entities.FindByClassname(null,"trigger_escape")){
		br.Kill()
	}
}




::rd_specifics_c7m3 <- function(){
	KillOldFinaleButton()
	EntFire("worldspawn", "RunScriptCode", "SpawnNewFinaleButton()", 1.0)
	EntFire("worldspawn", "RunScriptCode", "SpawnNewFinaleButton()", 1.0)
	EntFire("generator_start_model", "Disable", "", 1.5)
	EntFire("generator_start_model", "Enable", "", 2.0)
}




::SpawnNewFinaleButton <- function(){
	
	local keyvalues =
	{
		targetname = "generator_start_model",
		StartDisabled = "1",
		model = "models/props_vehicles/floodlight_generator_switch01.mdl",
		disableshadows = "1",
		UseDelay = "0",
		type = "2",
		origin = Vector(-456.187, -571.935, 2.57401),
		connections =
		{
			FinaleStart =
			{
				cmd1 = "bridge_ragdoll_fader�Enable��5�-1"
				cmd2 = "bridge_ragdoll_fader�Disable��8�-1"
				cmd3 = "bridge_move_sound�PlaySound��5�-1"
				cmd4 = "bridge_elevator�MoveToFloor�Bottom�5�-1"
				cmd5 = "store_brush�Enable��0�-1"
				cmd6 = "generator_brush�Enable��0�-1"
				//Editors Note: These � characters will not copy over properly. Websites cannot display them.
				//In Notepad++ replace them by selecting them, holding down ALT and entering 027 on Numblock. You'll get a black ESC character.	
			}
			FinaleEscapeStarted =
			{
				cmd1 = "relay_escape�Trigger��0�-1"
			}
		}
	}
	local ent = SpawnEntityFromTable("trigger_finale", keyvalues)
	NetProps.SetPropEntity(Entities.FindByName(null, "finale_start_button"), "m_sGlowEntity", ent)
}




// Convert all weapons in shop ( except deagle ) to weapon_grenade_launcher_spawn
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c1m2 <- function(){

	local ent = null
	local weapons =
	[
		"weapon_pistol_spawn",
		"weapon_autoshotgun_spawn",
		"weapon_chainsaw_spawn",
		"weapon_hunting_rifle_spawn",
		"weapon_pumpshotgun_spawn",
		"weapon_rifle_ak47_spawn",
		"weapon_rifle_desert_spawn",
		"weapon_rifle_m60_spawn",
		"weapon_rifle_sg552_spawn",
		"weapon_rifle_spawn",
		"weapon_shotgun_chrome_spawn",
		"weapon_shotgun_spas_spawn",
		"weapon_smg_mp5_spawn",
		"weapon_smg_silenced_spawn",
		"weapon_smg_spawn",
		"weapon_sniper_awp_spawn",
		"weapon_sniper_military_spawn",
		"weapon_sniper_scout_spawn"
	]
	
	foreach(weapon in weapons){
		while(ent = Entities.FindByClassname(ent, weapon)){
			SpawnEntityFromTable("weapon_grenade_launcher_spawn",
			{
				weaponskin = -1
				angles = ent.GetAngles().ToKVString()
				origin = ent.GetOrigin()
				spawnflags = 2
				body = 0
				solid = 0
				count = 1
				disableshadows = 0
				skin = 0
				glowrange = 0
				model = "models/w_models/weapons/w_grenade_launcher.mdl"
			})
			ent.Kill()
		}
	}
}




// Makes event glass also breakable by the rocket launcher's projectiles
// ----------------------------------------------------------------------------------------------------------------------------

::rd_specifics_c1m3 <- function(){
	local multiFilterOld = Entities.FindByName(null, "filter_breakglass")
	
	if(multiFilterOld && multiFilterOld.IsValid()){
		multiFilterOld.Kill()
	}
	

	SpawnEntityFromTable("filter_activator_class",
	{
			targetname = "filter_grenade_launcher_projectile"
			Negated = 0
			filterclass = "grenade_launcher_projectile"
	})
	
	SpawnEntityFromTable("filter_multi",
	{
		targetname = "filter_breakglass"
		Filter01 = "filter_bullet"
		Filter02 = "filter_melee"
		Filter03 = "filter_grenade_launcher_projectile"
		//
		filtertype = 1
		Negated = 0
	})
}
rd_meds
 
//****************************************************************************************
//																						//
//										rd_meds.nut										//
//																						//
//****************************************************************************************



// All mushroom triggers to iterate over
// ----------------------------------------------------------------------------------------------------------------------------

::medkit_triggers	<- []




// Returns handle of the created prop_dynamic with a 'mushroom model'
// ----------------------------------------------------------------------------------------------------------------------------

::RD_healtkit_model <- function(pos, ang, shroomdata){
	local model = SpawnEntityFromTable("prop_dynamic_override",
	{
		// General
		targetname = "RD_HP_MODEL", origin = pos, angles = ang, body = 0, DefaultAnim = "idle", DisableBoneFollowers = 1,
		// Shadows and fade
		disablereceiveshadows = 1, disableshadows = 1, disableX360 = 0, ExplodeDamage = 0, ExplodeRadius = 0, fademaxdist = 0, fademindist = -1, fadescale = 0,
		// Glows
		glowbackfacemult = 1.0, glowcolor = shroomdata.glowColor, glowrange = shroomdata.glowRange, glowrangemin = 0, glowstate = shroomdata.glowstate, health = 0,
		// Model & Animation
		LagCompensate = 0, MaxAnimTime = 10, maxcpulevel = 0, maxgpulevel = 0, MinAnimTime = 5,
		mincpulevel = 0, mingpulevel = 0, model = "models/props_collectables/mushrooms_glowing.mdl", PerformanceMode = 0, pressuredelay = 0,
		RandomAnimation = 0, renderamt = 255, rendercolor = shroomdata.modelColor, renderfx = 0, rendermode = 0, SetBodyGroup = 0, skin = 0,
		solid = 0, spawnflags = 0, updatechildren = 0
	})
	model.SetModelScale(shroomdata.modelScaleMax, 0)
	return model
}




// Creates a survivor only filter for the mushrooms
// ----------------------------------------------------------------------------------------------------------------------------

SpawnEntityFromTable("filter_activator_team", { targetname = "RD_FILTER_SURVIVOR", origin = Vector(0,0,0), Negated = 0, filterteam = 2 } )
::worldspawn <- Entities.FindByClassname(null, "worldspawn")
::worldspawn.ValidateScriptScope()




// Returns handle of trigger to execute the healing function
// ----------------------------------------------------------------------------------------------------------------------------

::RD_healthkit_trigger <- function(pos, shroomdata){
	local triggerMin = shroomdata.triggerSize[0]
	local triggerMax = shroomdata.triggerSize[1]
	local zOffset = triggerMax.z
	local HP_Value = shroomdata.hp
	
	local triggerName = "RD_HP_TRIGGER"
	//
	local triggerTable =
	{
		targetname    = triggerName
		StartDisabled = 0
		spawnflags    = 1
		allowincap    = 1
		entireteam    = 0
		filtername    = "RD_FILTER_SURVIVOR"
		origin        = pos + Vector(0,0,zOffset)
	}

	local trigger = SpawnEntityFromTable( "trigger_multiple", triggerTable)
	//
	setTriggerSize(trigger,triggerMin,triggerMax)
	NetProps.SetPropInt(trigger, "m_Collision.m_nSolidType", 2)
	//
	EntFire( triggerName, "AddOutput", "OnStartTouch worldspawn:RunScriptCode:survivorMedKitTouch(activator):0:-1" )
	EntFire( triggerName, "AddOutput", "OnTouching worldspawn:RunScriptCode:survivorMedKitTouch(activator):0:-1" )
	//
	if(DevModeActive()){
		DebugDrawBox( triggerTable.origin, Vector(32,32,32), Vector(-32,-32,-32), 255, 255, 255, 0, 16)
	}
	return trigger
}




// Sets the trigger size in relation to the mushroom size
// ----------------------------------------------------------------------------------------------------------------------------

function setTriggerSize(trigger, vectorMins, vectorMaxs){
	if(trigger.IsValid()){
		if(typeof(vectorMins) == "Vector"){
			if(typeof(vectorMaxs) == "Vector"){
				NetProps.SetPropVector(trigger, "m_Collision.m_vecMins", vectorMins)
				NetProps.SetPropVector(trigger, "m_Collision.m_vecMaxs", vectorMaxs)
			}else{
				error("setTriggerSize error: vectorMaxs ment to be datatype vector")
			}
		}else{
			error("setTriggerSize error: vectorMins ment to be datatype vector")
		}
	}
}




// Creates a set of trigger and prop_dynamic_override ( healing mushroom )
// ----------------------------------------------------------------------------------------------------------------------------

::createRD_Medkit <- function(pos, ang, rotating, shroomdata){
	local HP_Val = shroomdata.hp

	local trigger = RD_healthkit_trigger(pos, shroomdata);
	local model = RD_healtkit_model(pos, ang, shroomdata);
	
	local mushroomTable =
	{
		model = model
		trigger = trigger
		restoreTime = shroomdata.restoreTime
		usetime = Time() - shroomdata.restoreTime
		usable = true
		hp = HP_Val
		modelScaleMin = shroomdata.modelScaleMin
		modelScaleMax = shroomdata.modelScaleMax
		glowstate = shroomdata.glowstate
		action = shroomdata.action
		flashColor = shroomdata.flashColor
	}
	medkit_triggers.append(trigger)
	
	addTableToEntityScope(trigger, mushroomTable)
	addTableToEntityScope(model, mushroomTable)
	
	if(rotating){
		AttachRotatorTo(model)
	}
}

::addTableToEntityScope <- function(ent, table){
	
	local scope = GetValidatedScriptScope(ent)
	
	foreach(key, value in table){
		scope[key] <- value
	}
}




// Mushrooms properties
// ----------------------------------------------------------------------------------------------------------------------------
::shroomProperties <-
{
	large 	= 	{ hp = 75, action = "HP", restoreTime = 16, modelColor = "255 185 0", flashColor = "255 185 0", glowRange = 256, glowstate = 3, glowColor = "255 185 0", GlowColorRelation = true, modelScaleMax = 7.0, modelScaleMin = 1.0, triggerSize = [ Vector(-28,-28,-28), Vector(28,28,28) ] }
	medium 	=	{ hp = 50, action = "HP", restoreTime = 16, modelColor = "220 0 255", flashColor = "220 0 255", glowRange = 256, glowstate = 3, glowColor = "220 0 255", GlowColorRelation = true, modelScaleMax = 5.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
	small	=	{ hp = 25, action = "HP", restoreTime = 16, modelColor = "0 105 255", flashColor = "0 105 255", glowRange = 256, glowstate = 3, glowColor = "0 105 255", GlowColorRelation = true, modelScaleMax = 3.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
	tiny	=	{ hp = 10, action = "HP", restoreTime = 16, modelColor = "255 255 255", flashColor = "255 255 255", glowRange = 256, glowstate = 3, glowColor = "255 255 255", GlowColorRelation = true, modelScaleMax = 2.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
	exp		=	{ hp = 0, action = "EXP", restoreTime = 8, modelColor = "0 0 0", flashColor = "0 0 0", glowRange = 128, glowstate = 3, glowColor = "255 0 0", GlowColorRelation = false, modelScaleMax = 4.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
	item	=	{ hp = 0, action = "ITEM", restoreTime = 16, modelColor = "0 0 255", flashColor = "0 0 255", glowRange = 512, glowstate = 3, glowColor = "0 0 255", GlowColorRelation = true, modelScaleMax = 4.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
	bh		=	{ hp = 0, action = "BH", restoreTime = 1, modelColor = "0 255 0", flashColor = "0 255 0", glowRange = 1024, glowstate = 3, glowColor = "0 255 0", GlowColorRelation = true, modelScaleMax = 4.0, modelScaleMin = 1.0, triggerSize = [ Vector(-16,-16,-16), Vector(16,16,16) ] }
}

foreach(dataset in shroomProperties){
	if(dataset.glowstate == 3 && dataset.GlowColorRelation){
		dataset.glowColor = getColorWithIntensity(dataset.modelColor, 77)
	}
}




// After a mushroom heals a player it should be invisible for 10 seconds
// ----------------------------------------------------------------------------------------------------------------------------

::setMedVisibility <- function(x, ent){
	
	local scope = GetValidatedScriptScope(ent)
	
	if(x == 0){
		NetProps.SetPropInt(ent, "m_Glow.m_iGlowType", 0)
		NetProps.SetPropInt(ent, "m_fEffects", NetProps.GetPropInt(ent, "m_fEffects") | (1 << 5))
		mushroomSizer(ent,scope.modelScaleMin, 0)
	}else{
		NetProps.SetPropInt(ent, "m_fEffects", 0)
		NetProps.SetPropInt(ent, "m_Glow.m_iGlowType", scope.glowstate)
		mushroomSizer(ent,scope.modelScaleMax, 0.1)
		EmitAmbientSoundOn("level/popup.wav", 1, 100, 100, ent)
	}
}




// Let's the mushroom "grow"
// ----------------------------------------------------------------------------------------------------------------------------

::mushroomSizer <- function(ent, scale, time){
	ent.SetModelScale(scale, time)
}




// Survivor touches a mushroom trigger
// ----------------------------------------------------------------------------------------------------------------------------

::survivorMedKitTouch <- function(player){
	
	// Has to be set when this fuction gets called via OnTouching because the activator is the trigger itself
	
	if(player.GetClassname() == "trigger_multiple"){
		player = Entities.FindByClassnameNearest("player", player.GetOrigin(), 256)
	}
	
	local playerPos = player.GetOrigin()
	local medkit_trigger = Entities.FindByNameNearest("RD_HP_TRIGGER", playerPos, 256)
	
	local scope = GetValidatedScriptScope(medkit_trigger)
	
	local HP_Val = scope.hp
	local action = scope.action
	local flashColor = split(scope.flashColor," ")
	
	local medkit_model = scope.model
	local mushroomUsed = false
	
	if(!IsPlayerABot(player)){
		if(!missionFailed){
			if(Time() >= scope.usetime + scope.restoreTime){
				if(action == "HP"){
					if(player.GetHealth() < player.GetMaxHealth() || player.IsIncapacitated()){
						healPlayer(player, HP_Val)
						mushroomUsed = true
					}
				}else if(action == "BH"){
					if(!(player in bunnyPlayers)){
						playerBecomesBunny(player)
						player.UseAdrenaline(7)
						mushroomUsed = true
					}
				}else if(action == "EXP"){
					executeExplosion(medkit_trigger)
					mushroomUsed = true
				}else if(action == "ITEM"){
					if(!player.IsIncapacitated()){
						local invTable = {}
						GetInvTable(player, invTable)
						if(!("slot2" in invTable)){
							giveRandomItem(player, medkit_trigger)
							mushroomUsed = true
						}
					}
				}
				if(mushroomUsed){
					scope.usetime = Time()
					scope.usable = false
					setMedVisibility(0, medkit_model)
					ScreenFade(player, flashColor[0].tointeger(), flashColor[1].tointeger(), flashColor[2].tointeger(), 128, 1.0, 0, 1)
				}
			}
		}
	}
}




// Sounds used by the mushrooms 
// ----------------------------------------------------------------------------------------------------------------------------

::mushroomSounds <-
{
	explosions =
	[
		"player/boomer/explode/explo_medium_09.wav",
		"player/boomer/explode/explo_medium_10.wav",
		"player/boomer/explode/explo_medium_14.wav"
	]
	misc =
	[
		"level/gnomeftw.wav",
		"player/laser_on.wav",
		"ui/menu_invalid.wav"
	]
}





::precacheSounds <- function(){
	foreach(collection in mushroomSounds){
		foreach(sound in collection){
			PrecacheSound(sound)
		}
	}
}




// Mushroom action ( explosion )
// ----------------------------------------------------------------------------------------------------------------------------

::executeExplosion <- function(ent){
	local location = ent.GetOrigin()
	local expTable =
	{
		origin = location
		fireballsprite = "sprites/zerogxplode.spr"
		ignoredClass = 0
		targetname = "exp"
		iMagnitude = 128
		spawnflags = 0
		iRadiusOverride = 128
		rendermode = 5
	}
	
	local exp = SpawnEntityFromTable("env_explosion", expTable)
	DoEntFire("!self", "explode", "", 0, exp, exp)
	local sounds = mushroomSounds.explosions
	EmitAmbientSoundOn(sounds[RandomInt(0, sounds.len() - 1)], 0.8, 100, 147, ent)
}




// Mushroom action ( bunny-hop )
// ----------------------------------------------------------------------------------------------------------------------------

::playerBecomesBunny <- function(player){
	if(!(player in bunnyPlayers)){
		if(player.IsValid()){
			bunnyPlayers[player] <- player
			ClientPrint(null, 5, "\x03" + player.GetPlayerName() + "\x01" + " is a bunny now.")
			EmitAmbientSoundOn("player/laser_on.wav", 1, 100, 180, player)
		}
	}
}




// Mushroom action ( random item )
// ----------------------------------------------------------------------------------------------------------------------------

::giveRandomItem <- function(player, shroom){
	local throwables = [ "weapon_pipe_bomb", "weapon_vomitjar", "weapon_molotov" ]
	player.GiveItem(throwables[RandomInt(0, throwables.len() - 1)])
	EmitAmbientSoundOn(mushroomSounds.misc[0], 0.5, 100, 170, shroom)
}




// Mushroom action ( healing )
// ----------------------------------------------------------------------------------------------------------------------------

::healPlayer <- function(player, val){
	
	local sndPitch = 100;
	switch(GetCharacterDisplayName(player)){
		case "Rochelle"	:	sndPitch = 115; break;
		case "Zoey"		: 	sndPitch = 135; break;
		default			: 	sndPitch = 100; break;
	}
	
	EmitAmbientSoundOn("player/items/pain_pills/pills_use_1.wav", 1, 100, sndPitch, player)
	StopAmbientSoundOn("player/heartbeatloop.wav", player) 
	player.UseAdrenaline(7)
	local newHP = player.GetHealth() + val
	local playerMaxHealth = player.GetMaxHealth()
	
	if(player.IsIncapacitated())
	{
		player.ReviveFromIncap()
		player.SetReviveCount(0)
		player.SetHealthBuffer(0)
		player.SetHealth(val)
	}
	else
	{
		if(newHP >= playerMaxHealth)
		{
			//NetProps.SetPropInt(player,"m_isGoingToDie",0)
			//NetProps.SetPropInt(player,"m_isIncapacitated",0)
			player.ReviveFromIncap()
			player.SetReviveCount(0)
			player.SetHealthBuffer(0)
			player.SetHealth(playerMaxHealth)
		}
		else
		{
			//NetProps.SetPropInt(player,"m_isGoingToDie",0)
			//NetProps.SetPropInt(player,"m_isIncapacitated",0)
			player.ReviveFromIncap()
			player.SetReviveCount(0)
			player.SetHealthBuffer(0)
			player.SetHealth(newHP)
		}
	}
}




// Called "OnGameplayStart" it will spawn mushrooms for the current map 
// ----------------------------------------------------------------------------------------------------------------------------

spawnMushrooms <- function(){
	if(mapName in mushroomPositions){
		foreach(DS in mushroomPositions[mapName]){
			createRD_Medkit(DS.origin, DS.angles, DS.rotating, shroomProperties[DS.type])
		}
	}
}




// When specified in mushroom definition the passed entity gets attached to a rotation entity
// ----------------------------------------------------------------------------------------------------------------------------

AttachRotatorTo <- function(ent){
	local pos = ent.GetOrigin()
	local rotName = UniqueString("_mushroom_rot")
	local rotator = SpawnEntityFromTable("func_rotating", { targetname = rotName, origin = pos, spawnflags = 67})
	NetProps.SetPropVector(rotator, "m_Collision.m_vecMins", Vector(1,1,1))
	NetProps.SetPropVector(rotator, "m_Collision.m_vecMaxs", Vector(-1,-1,-1))
	DoEntFire("!self", "SetParent", "!activator", 0.00, rotator, ent);

}
rd_melee_getter
 
//****************************************************************************************
//																						//
//									rd_melee_getter.nut									//
//																						//
//****************************************************************************************

sharpMeleeData <-
[
	{ model = "models/v_models/weapons/v_knife_t.mdl", itemName = "knife", alias = "knife" },
	{ model = "models/weapons/melee/v_crowbar.mdl", itemName = "crowbar", alias = "crowbar" },
	{ model = "models/weapons/melee/v_fireaxe.mdl", itemName = "fireaxe", alias = "fireaxe" },
	{ model = "models/weapons/melee/v_katana.mdl", itemName = "katana", alias = "katana" },
	{ model = "models/weapons/melee/v_machete.mdl", itemName = "machete", alias = "machete" },
	{ model = "models/weapons/melee/v_pitchfork.mdl", itemName = "pitchfork", alias = "pitchfork" }
]

bluntMeleeData <-
[
	{ model = "models/weapons/melee/v_riotshield.mdl", itemName = "riotshield" , alias = "riotshield" },
	{ model = "models/weapons/melee/v_shovel.mdl", itemName = "shovel", alias = "shovel" },
	{ model = "models/weapons/melee/v_bat.mdl", itemName = "baseball_bat", alias = "bat" },
	{ model = "models/weapons/melee/v_cricket_bat.mdl", itemName = "cricket_bat", alias = "cricket" },
	{ model = "models/weapons/melee/v_golfclub.mdl", itemName = "golfclub", alias = "golfclub" },
	{ model = "models/weapons/melee/v_tonfa.mdl", itemName = "tonfa", alias = "tonfa" },
	{ model = "models/weapons/melee/v_electric_guitar.mdl", itemName = "electric_guitar", alias = "guitar" },
	{ model = "models/weapons/melee/v_frying_pan.mdl", itemName = "frying_pan", alias = "pan" }
]




// Before giving the melee check if it's available for the current map
// ----------------------------------------------------------------------------------------------------------------------------

function GiveMelee(player, melee){

	if(meleeAliases == null){
		meleeAliases = getAvailableMeleeAliases()
	}

	local sharps = GetAvailableSharpMelees()
	local blunts = GetAvailableBluntMelees()

	if(sharps.find(melee) != null || blunts.find(melee) != null){
		player.GiveItem(melee)
	}else{
		ClientPrint(null, 5, "The " + melee + " is not available on current map.")
		ClientPrint(null, 5, "Take one of those: " + meleeAliases)
	}
}

meleeAliases <- null;
function getAvailableMeleeAliases(){
	local aliases = "";
	foreach(dataSet in sharpMeleeData){
		if(IsModelPrecached(dataSet.model)){
			aliases += dataSet.alias + ", "
		}
	}
		foreach(dataSet in bluntMeleeData){
		if(IsModelPrecached(dataSet.model)){
			aliases += dataSet.alias + ", "
		}
	}
	return aliases;
}

function GetAvailableSharpMelees(){
	local sharps = []
	foreach(dataSet in sharpMeleeData){
		if(IsModelPrecached(dataSet.model)){
			sharps.append(dataSet.itemName)
		}
	}
	return sharps;
}

function GetAvailableBluntMelees(){
	local blunts = []
	foreach(dataSet in bluntMeleeData){
		if(IsModelPrecached(dataSet.model)){
			blunts.append(dataSet.itemName)
		}
	}
	return blunts;
}




// Will give the player a random sharp/blunt weapon depending which melee is available on the current map
// ----------------------------------------------------------------------------------------------------------------------------

function getAvailableMelee(attribute){
	local sharps = GetAvailableSharpMelees()
	local blunts = GetAvailableBluntMelees()
	local melee = null;
	if(sharps.len() > 0 && blunts.len() > 0){
		if(attribute == "Sharp"){
			melee = sharps[RandomInt(0, sharps.len() - 1)]
		}else{
			melee = blunts[RandomInt(0, blunts.len() - 1)]
		}
		return melee;
	}else{
		return "bat"
	}
}
rd_mode_description
 
//****************************************************************************************
//																						//
//								rd_mode_description.nut									//
//																						//
//****************************************************************************************




// Output the most important facts about this mode to the players console
// ----------------------------------------------------------------------------------------------------------------------------

::printMutationInfo <- function(ent){
	
	local line = "_______________________________________________________________________________________________"
	local txt = [
	
		"-------------------------------- RocketDude by ReneTM --------------------------------"
		" "
		"In this mutation, there are no bot survivors and the human Survivors start with 200 health."
		"They are equipped with a Grenade Launcher with infinite ammo and clip size, and either a sharp melee weapon or a Magnum."
		"The Grenade Launcher's grenades do full damage to infected but only 1 to the survivors."
		"They travel in a straight line like in TF2. There are only pills and adrenaline shots to pickup."
		"All medkits and defibs are gone. There are different kinds of mushrooms spread over the map."
		"They can be picked up by walking over them. Some may be hard to reach."
		" "
		line
		" "
		" "
		" "
		" "
		"Green       : Server sided autobhop"
		"Dark Blue   : Random throwable if the players inventory allows it"
		"Black       : Explosive! I would not touch them"
		" "
		"Yellow      : +75 HP"
		"Pink        : +50 HP"
		"Blue        : +25 HP"
		"White       : +10 HP"
		" "
		"! Touching those health mushrooms also removes any tempoary health and \"black and white\" state !"
		line
		" "
		" "
		"Specialties:"
		" "
		"When all survivors are on the ground and the round would restart \"the last chance\" mode gets activated."
		"This mode being active, the survivors will have the chance, to get revived by killing any special or boss infected."
		"This mode can only be active once. Survivors will be black and white after this mode."
		"Destroying \"Skeeting\" tank-rocks mid-air will give you +5hp."
		"When you are incapped, but other survivors are still up, you can get revived by killing any special or boss infected."
		"Survivors are able to crawl while being incapped. Keep your eyes open for mushrooms."
		" "
		line
		" "
		" "
		"Chatcommands:"
		" "
		"!hud           -> Vote to enable/disable the timer hud"
		"!countdown     -> Vote to start a countdown while being in saferoom"
		" "
		"Local usage only:"
		"----------------"
		"!speedrunmode  -> Vote to toggle between speedrunmode which disables all infected and normal mode"
		"!saveangles    -> Annoyed by survivors looking the wrong direction? Save your eye angles :)"
		"!stats         -> Print players besttimes to console"
		"!r             -> Vote to jump back to the saferoom to retry"
	]
	
	foreach(line in txt){
		ClientPrint(ent, 5, GREEN + line)
	}
	for(local i = 0; i < 10; i++){
		ClientPrint(ent, 5, " ")
	}
	ClientPrint(ent, 5, GREEN + "Check the console for information!")
}
rd_saferoom_timer
 
//****************************************************************************************
//																						//
//									rd_saferoom_timer.nut								//
//																						//
//****************************************************************************************



::countDownActive		<- false
::countDownStamp		<- Time()
::countdownTime			<- 3

if(!IsSoundPrecached("ui/beep07.wav")){
	PrecacheSound("ui/beep07.wav")
}

if(!IsSoundPrecached("ui/beep22.wav")){
	PrecacheSound("ui/beep22.wav")
}




// Executed by the chatcommand !countdown it will check of everybody wants to make a countdown
// ----------------------------------------------------------------------------------------------------------------------------

::saferoomTimerUseStamp <- Time()

::startSafeRoomTimer <- function(ent){
	
	if(!AllInStartSafeRoom()){
		return
	}
	
	if(!(mapName in survivorSpawnPoints)){
		ClientPrint(null, 5, "This function is only available for maps of c1-c14.")
		return
	}
	
	if(NetProps.GetPropInt(Entities.FindByClassname(null, "terror_gamerules"), "m_bInIntro")){
		return
	}
	
	if(!(Time() > saferoomTimerUseStamp + 5)){
		ClientPrint(null, 5, "This function can only be used every 5 seconds.")
		return
	}

	local playerscope = GetValidatedScriptScope(ent)
	if(!("countdown_vote" in playerscope)){
		playerscope["countdown_vote"] <- true
		foreach(player in GetHumanSurvivors()){
			local playerscope = GetValidatedScriptScope(player)
			if(!("countdown_vote" in playerscope)){
				ClientPrint(null, 5, GREEN + ent.GetPlayerName() + WHITE + " voted to start a countdown.")
				return
			}
		}
	}
	
	if(!countDownActive){
		countDownActive = true
		countDownStamp = Time()
		FreezePlayers()
		SetPlayersStartPositions()
		saferoomTimerUseStamp = Time()
		foreach(player in GetHumanSurvivors()){
			player.ValidateScriptScope()
			player.GetScriptScope().rawdelete("countdown_vote")
		}
	}
}




// Gets called from Think() function
// ----------------------------------------------------------------------------------------------------------------------------

::safeRoomTimer <- function(){
	if(countDownActive){
		if(Time() > countDownStamp + 1){
			if(countdownTime > 0){
				printTimeToChat()
				countdownTime--
				countDownStamp = Time()
			}else{
				printGoToChat()
				countDownActive = false
				countdownTime = 3
			}
		}
	}
}




// Prints timer to chat and outputs sound to all players
// ----------------------------------------------------------------------------------------------------------------------------

::printTimeToChat <- function(){
	
	local players = GetHumanSurvivors()
	
	ClientPrint(null, 5,  GREEN + countdownTime)
	foreach(player in players){
		EmitAmbientSoundOn("ui/beep07.wav", 0.75, 100, 100, player)	
	}
}

::printGoToChat <- function(){

	local players = GetHumanSurvivors()

	ClientPrint(null, 5,  ORANGE + "GO!")
	UnfreezePlayers()
	foreach(player in players){
		EmitAmbientSoundOn("ui/beep22.wav", 0.75, 100, 100, player)
	}
}




// Check if all survivors are in the beginning saferoom ( Re-entering possible )
// ----------------------------------------------------------------------------------------------------------------------------

::AllInStartSafeRoom <- function(){
	foreach(player in GetHumanSurvivors()){
		if(ResponseCriteria.GetValue(player, "instartarea" ) == "0"){
			return false
		}
	}
	return true
}


::FreezePlayers <- function(){
	foreach(player in GetHumanSurvivors()){
		NetProps.SetPropInt(player, "movetype", 0)
	}
}

::UnfreezePlayers <- function(){
	foreach(player in GetHumanSurvivors()){
		NetProps.SetPropInt(player, "movetype", 2)
	}	
}




// Sets the origin of all present players to one of in the saferoom positioned info_survivor_position entities.
// This method is only ment to be used when all survivors are in the saferoom!
// ----------------------------------------------------------------------------------------------------------------------------

::SetPlayersStartPositions <- function(){

	local offsets = [ Vector(16,16,0), Vector(16,-16,0), Vector(-16,-16,0), Vector(-16,16,0) ]
	
	local counter = 0
	
	foreach(player in GetHumanSurvivors()){
		if(counter == 4){
			counter = 0
		}
		player.SetOrigin(survivorSpawnPoints[ mapName ] + offsets[counter])
		counter++
	}
}




// These are player origins for all beginning saferooms ( c1-c14 ). We spawn every player with an offset
// ----------------------------------------------------------------------------------------------------------------------------

::survivorSpawnPoints <-
{
	c1m1_hotel				= Vector(599.989,5630.53,2851.46)
	c1m2_streets			= Vector(2360.92,5124.73,452.031)
	c1m3_mall				= Vector(6628.92,-1433.91,28.0313)
	c1m4_atrium				= Vector(-2090.7,-4624.16,540.031)

	c2m1_highway			= Vector(10895.7,7873.87,-548.574)
	c2m2_fairgrounds		= Vector(1636.83,2719.81,8.03125)
	c2m3_coaster			= Vector(4343.23,2048.8,-59.9688)
 	c2m4_barns				= Vector(3116.18,3330.29,-183.969)
	c2m5_concert			= Vector(-825.861,2292.01,-251.969)

	c3m1_plankcountry		= Vector(-12546.3,10456.1,248.893)
	c3m2_swamp 				= Vector(-8160.61,7615.23,16.0313)
	c3m3_shantytown			= Vector(-5709.34,2143.82,140.031)
	c3m4_plantation			= Vector(-5011.12,-1672.01,-92.8118)
	
	c4m1_milltown_a			= Vector(-7073.8,7719.17,117.924)
	c4m2_sugarmill_a		= Vector(3628.58,-1679.04,236.531)
	c4m3_sugarmill_b		= Vector(-1803.96,-13698.4,134.031)
	c4m4_milltown_b			= Vector(3910.57,-1569.59,236.281)
	c4m5_milltown_escape 	= Vector(-3367.6,7853.06,124.031)
	
	c5m1_waterfront			= Vector(798.114,676.213,-477.969)
	c5m2_park				= Vector(-3966.59,-1261.61,-339.969)
	c5m3_cemetery			= Vector(6402.67,8410.15,4.03125)
	c5m4_quarter			= Vector(-3291.22,4889.5,72.0313)
	c5m5_bridge				= Vector(-12039.5,5833.28,132.031)

	c6m1_riverbank			= Vector(911.249,3774.63,98.0062)
	c6m2_bedlam				= Vector(3157.03,-1218.18,-291.969)
	c6m3_port				= Vector(-2410.05,-456.402,-251.969)
	
	c7m1_docks				= Vector(13838.7,2583.8,36.2599)
	c7m2_barge				= Vector(10726.2,2445.25,180.031)
	c7m3_port				= Vector(1123.67,3230.13,174.531)
	
	c8m1_apartment			= Vector(2004.74,913.544,436.031)
	c8m2_subway				= Vector(2907.06,3063.35,20.0313)
	c8m3_sewers				= Vector(10948.2,4729.64,20.0313)
	c8m4_interior			= Vector(12376.7,12567.9,20.0313)
	c8m5_rooftop			= Vector(5405.11,8388.72,5540.03)

	c9m1_alleys				= Vector(-9951.59,-8578.78,-2.66612)
	c9m2_lots				= Vector(278.24,-1301.6,-171.969)
	
	c10m1_caves				= Vector(-11745.4,-14862.1,-214.225)
	c10m2_drainage 			= Vector(-11014.6,-9103.6,-587.969)
	c10m3_ranchhouse		= Vector(-8263.9,-5550.87,-20.9688)
	c10m4_mainstreet		= Vector(-3082.28,-23.326,164.031)
	c10m5_houseboat			= Vector(2120.59,4742.14,-59.9688)
	
	c11m1_greenhouse		= Vector(6815.1,-672.996,772.031)
	c11m2_offices			= Vector(5278.98,2785.43,52.0313)
	c11m3_garage			= Vector(-5368.26,-3069.3,20.0313)
	c11m4_terminal			= Vector(-447.003,3577.39,300.031)
	c11m5_runway			= Vector(-6716.97,12066.8,156.031)
	
	c12m1_hilltop			= Vector(-8073.41,-15118.7,283.495)
	c12m2_traintunnel		= Vector(-6611.49,-6712.19,352.031)
	c12m3_bridge			= Vector(-927.759,-10382.7,-59.9688)
	c12m4_barn				= Vector(7754.14,-11374,444.031)
	c12m5_cornfield			= Vector(10480.9,-566.041,-24.9688)
	
	c13m1_alpinecreek		= Vector(-3012.43,-589.132,68.0313)
	c13m2_southpinestream	= Vector(8566.48,7505.06,500.031)
	c13m3_memorialbridge	= Vector(-4372.79,-5150.93,100.031)
	c13m4_cutthroatcreek	= Vector(-3387.78,-9284.08,364.031)
	
	c14m1_junkyard			= Vector(-4189.09,-10697.9,-296.294)
	c14m2_lighthouse		= Vector(2220.41,-1103.17,452.031)
}




// Prevent players from using restartFromSaferoom on a finale
// ----------------------------------------------------------------------------------------------------------------------------

::valveFinaleMaps <-
[
	"c1m4_atrium"
	"c2m5_concert"
	"c3m4_plantation"
	"c4m5_milltown_escape"
	"c5m5_bridge"
	"c6m3_port"
	"c7m3_port"
	"c8m5_rooftop"
	"c9m2_lots"
	"c10m5_houseboat"
	"c11m5_runway"
	"c12m5_cornfield"
	"c13m4_cutthroatcreek"
	"c14m2_lighthouse"
]




//insafespot
//incheckpoint
rd_speedrun_mode
 
//****************************************************************************************
//																						//
//										rd_speedrun_mode.nut							//
//																						//
//****************************************************************************************




// Playing locally allows the player to enable the speedrun mode.
// !speedrunmode to toggle it. !r to respawn in the saferoom
// ----------------------------------------------------------------------------------------------------------------------------

::speedrunModeEnabled <- false

::speedrunModeToggle <- function(ent){
	
	if(!OnLocalServer()){
		return
	}
	
	ent.ValidateScriptScope()
	local scope = ent.GetScriptScope()
	scope["speedrun_mode"] <- true
	
	foreach(player in GetHumanSurvivors()){
		local playerscope = player.GetScriptScope()
		if(!("speedrun_mode" in playerscope)){
			ClientPrint(null, 5, GREEN + ent.GetPlayerName() + WHITE + " voted to " + ( speedrunModeEnabled ? "disable" : "enable" ) + " the speedrun mode!")
			return
		}
	}
	
	speedrunModeEnabled = !speedrunModeEnabled
	
	local speedrunDirector =
	{
		ProhibitBosses	= [true, false]
		MobMaxSize		= [0, 30]
		CommonLimit		= [0, 30]
		MobSpawnMinTime	= [9999, 90]
		MobSpawnMaxTime	= [9999, 180]
		MaxSpecials		= [0, 6]
		SpecialRespawnInterval = [9999, 45]
	}
	
	foreach(var,valarr in speedrunDirector){
		if(speedrunModeEnabled){
			SessionOptions[var.tostring()] <- valarr[0]
			removeAllInfected()
		}else{
			SessionOptions[var.tostring()] <- valarr[1]
		}
	}
	
	foreach(player in GetHumanSurvivors()){
		player.GetScriptScope().rawdelete("speedrun_mode")
	}
	
	ClientPrint(null, 5, WHITE + "Speedrun mode " + GREEN + ( speedrunModeEnabled ? "enabled" : "disabled") )
}




// While being in speedrun mode the survivor can jump back to the saferoom to restart his run
// ----------------------------------------------------------------------------------------------------------------------------

::restartFromSaferoom <- function(ent){
	
	if(!speedrunModeEnabled){
		ClientPrint(null, 5, WHITE + "Jumping back to the saferoom is restricted to " + GREEN + "speedrunmode!")
		return
	}
	
	if(!(Director.GetMapName() in survivorSpawnPoints)){
		return
	}
	
	if(valveFinaleMaps.find(Director.GetMapName()) != null){
		ClientPrint(null, 5, WHITE + "Jumping back to the saferoom is disabled for finales")
		return
	}
	
	local scope = GetValidatedScriptScope(ent)
	
	scope["go_back_2_safe"] <- true
	
	foreach(player in GetHumanSurvivors()){
		local playerscope = player.GetScriptScope()
		if(!("go_back_2_safe" in playerscope)){
			ClientPrint(null, 5, GREEN + ent.GetPlayerName() + WHITE + " voted to go back to the saferoom!")
			return
		}
	}
	
	foreach(player in GetHumanSurvivors()){
		local playerscope = GetValidatedScriptScope(player)
		playerscope.rawdelete("go_back_2_safe")
		local prevBest = PlayerTimeData[player].time_best
		PlayerTimeData[player] <- { timerActive = false, finished = false, startTime = Time(), endTime = Time(), time_best = prevBest, ticks = 0, seconds = 0 }
		bunnyPlayers.rawdelete(player)
		NetProps.SetPropInt(player, "m_afButtonDisabled", NetProps.GetPropInt(player, "m_afButtonDisabled") & ~2)
		GLOBALS.allowBulletTime = false
		
		// Set player eye angles when there are any saved
		if(player in SavedplayerEyeAngles){
			player.SnapEyeAngles(SavedplayerEyeAngles[player].EyeAngles)
		}
		player.SetVelocity(Vector(0,0,256))
	}
	
	SetPlayersStartPositions()
	setPlayersHealth()
}




// Prints all times of known maps to the console
// ----------------------------------------------------------------------------------------------------------------------------

::outputStats <- function(ent){
	
	if(ent != GetListenServerHost()){
		return
	}
	
	foreach(mapname in valveMaps){
		local str = null
		str = FileToString("rocketdude/speedrun/" + mapname + ".txt")
		if(str != null){
			str = strip(str)
			if(isNumeric(str)){
				ClientPrint(ent, 5, GREEN + mapname + GetCharChain(" ", 32 - mapname.len()) + ": " + str)
			}else{
				ClientPrint(ent, 5, ORANGE + mapname + GetCharChain(" ", 32 - mapname.len()) + ": INVALID DATA IN TEXT FILE")
			}
		}else{
			ClientPrint(ent, 5, BLUE + mapname + GetCharChain(" ", 32 - mapname.len()) + ": NO RECORD YET")
		}
	}
	for(local i = 0; i < 10; i++){
		ClientPrint(ent, 5, " ")
	}
	ClientPrint(ent, 5, GREEN + "Check the console for your stats!")
}




// Removes all infected like nb_delete_all does
// ----------------------------------------------------------------------------------------------------------------------------

::removeAllInfected <- function(){
	local player = null
	local witch = null
	local common = null
	
	while(player = Entities.FindByClassname(player, "player")){
		if(IsPlayerABot(player) && player.GetZombieType() != 9){
			player.Kill()
		}
	}
	
	while(witch = Entities.FindByClassname(witch, "witch")){
		if(witch.IsValid()){
			witch.Kill()
		}
	}
	
	while(common = Entities.FindByClassname(common, "infected")){
		if(common.IsValid()){
			common.Kill()
		}
	}
}




// Save player angles for speedrunning
// ----------------------------------------------------------------------------------------------------------------------------

::SavedplayerEyeAngles <- {}

function savePlayerEyeAngles(ent){
	
	if(!OnLocalServer()){
		ClientPrint(null, 5, WHITE + "Saving player angles is restricted to local servers!")
		return
	}
	
	if(!speedrunModeEnabled){
		ClientPrint(null, 5, WHITE + "Enable speedrunmode first ( " + GREEN + "!speedrunmode" + WHITE + " in chat )!")
		return
	}
	
	if(ResponseCriteria.GetValue(ent, "instartarea" ) == "0"){
		ClientPrint(null, 5, WHITE + "Move to the start area to save your eye angles!")
		return
	}
	
	if(ent.IsValid()){
		SavedplayerEyeAngles[ent] <- { EyeAngles = ent.EyeAngles() }
		ClientPrint(null, 5, WHITE + "Your eye angles got " + GREEN + "saved!")
	}
}
rd_utils
 
//****************************************************************************************
//																						//
//										rd_utils.nut									//
//																						//
//****************************************************************************************


getroottable()["TRACE_MASK_ALL"] <- -1
getroottable()["TRACE_MASK_SHOT"] <- 1174421507
getroottable()["TRACE_MASK_VISION"] <- 33579073
getroottable()["TRACE_MASK_NPC_SOLID"] <- 33701899
getroottable()["TRACE_MASK_PLAYER_SOLID"] <- 33636363
getroottable()["TRACE_MASK_VISIBLE_AND_NPCS"] <- 33579137


getroottable()["WHITE"]		<- "\x01"
getroottable()["BLUE"]		<- "\x03"
getroottable()["ORANGE"]	<- "\x04"
getroottable()["GREEN"]		<- "\x05"


::ZombieTypes <-
{
	COMMON		= 0
	SMOKER		= 1
	BOOMER		= 2
	HUNTER		= 3
	SPITTER		= 4
	JOCKEY		= 5
	CHARGER		= 6
	WITCH		= 7
	TANK		= 8
	SURVIVOR	= 9
	MOB			= 10
	WITCHBRIDE	= 11
	MUDMEN		= 12
}

::TEAMS <-
{ 
	SPECTATOR	= 1
	SURVIVOR	= 2
	INFECTED	= 3
}

::damageTypes <-
{
	GENERIC			= 0
	CRUSH			= 1
	BULLET			= 2
	SLASH			= 4
	BURN			= 8
	VEHICLE			= 16
	FALL			= 32
	BLAST			= 64
	CLUB			= 128
	SHOCK			= 256
	SONIC			= 512
	ENERGYBEAM		= 1024
	DROWN			= 16384
	PARALYSE		= 32768
	NERVEGAS		= 65536
	POISON			= 131072
	RADIATION		= 262144
	DROWNRECOVER	= 524288
	ACID			= 1048576
	SLOWBURN		= 2097152
	REMOVENORAGDOLL	= 4194304
}


// Creates the think timer which calls "Think()" every tick
// ----------------------------------------------------------------------------------------------------------------------------

function createThinkTimer(){
	local timer = null
	while (timer = Entities.FindByName(null, "thinkTimer")){
		timer.Kill()
	}
	timer = SpawnEntityFromTable("logic_timer", { targetname = "thinkTimer", RefireTime = 0.01 })
	timer.ValidateScriptScope()
	timer.GetScriptScope()["scope"] <- this

	timer.GetScriptScope()["func"] <- function (){
		scope.Think()
	}
	timer.ConnectOutput("OnTimer", "func")
	EntFire("!self", "Enable", null, 0, timer)
}




// Remove all deathcams e.g on c8m5_rooftop
// ----------------------------------------------------------------------------------------------------------------------------

function removeDeathFallCameras(){
	local deathCam = null
	while (deathCam = Entities.FindByClassname(deathCam, "point_deathfall_camera")){
		deathCam.Kill()
	}
}




// All needed cvars
// ----------------------------------------------------------------------------------------------------------------------------

::cvars <-
{
	//Survivor settings
	sv_infinite_ammo = 1
	survivor_allow_crawling = 1
	survivor_crawl_speed = 45
	first_aid_kit_max_heal = 200
	survivor_respawn_with_guns = 0
	first_aid_heal_percent = 0.8
	z_grab_ledges_solo = 1
	z_tank_incapacitated_decay_rate = 5
	//Grenadelauncher settings
	grenadelauncher_velocity = 1100
	grenadelauncher_startpos_right = 0
	grenadelauncher_startpos_forward = 16
	grenadelauncher_vel_variance = 0
	grenadelauncher_vel_up = 0
	//Force settings
	phys_explosion_force = 4096
	melee_force_scalar = 16
	melee_force_scalar_combat_character = 512
	phys_pushscale = 512
	//Infected settings
	z_force_attack_from_sound_range = 512
	z_brawl_chance = 1
	//Medicals
	pain_pills_health_threshold = 199
	pain_pills_health_value = 100
	//Items
	sv_infected_riot_control_tonfa_probability = 0
	sv_infected_ceda_vomitjar_probability = 0
	//Votes
	sv_vote_creation_timer = 8
	sv_vote_plr_map_limit = 128
	//Misc
	z_spawn_flow_limit = 99999
	director_afk_timeout = 99999
	mp_allowspectators = 0
}




local cvarChangeTime = Time()

function checkCvars(){
	if(Time() > cvarChangeTime + 4){
		foreach(var, value in cvars){
			if(Convars.GetFloat(var) != value.tofloat()){
				Convars.SetValue(var, value)
			}
		}
		cvarChangeTime = Time()
	}
}




// Create a func_timescale entity for the "bullet time"
// ----------------------------------------------------------------------------------------------------------------------------

timeScaler <- null
function createBulletTimerEntity(){
	while (timeScaler = Entities.FindByName(null, "timeScaler")){
		timeScaler.Kill()
	}
	timeScaler = SpawnEntityFromTable("func_timescale",
		{
			targetname = "timeScaler"
			acceleration = 0.05
			angles = "0 0 0"
			origin = Vector(0, 0, 0)
			blendDataMultiplier = 3.0
			minBlendRate = 0.1
			desiredTimescale = 0.25
		}
	)
}




// We roll a dice with probability of X to decide if event Y will occur 
// ----------------------------------------------------------------------------------------------------------------------------

function rollDice(probability){
	local roll = RandomInt(1, 100)
	
	if(probability == 100){
		return true
	}else if(roll <= probability){
		return true
	}
	return false
}




// Returns the closest survivor in any radius
// ----------------------------------------------------------------------------------------------------------------------------

function getClosestSurvivorTo(ent){
	local survivor = null
	local previousDistance = 0.0
	local closest = null
	local currentDistance = null
	
	foreach(survivor in GetSurvivors()){
		if(survivor != ent){
			if(previousDistance == 0.0){
				previousDistance = (ent.GetOrigin() - survivor.GetOrigin()).Length()
				closest = survivor
			}else{
				currentDistance = (ent.GetOrigin() - survivor.GetOrigin()).Length()
				if(currentDistance < previousDistance){
					previousDistance = currentDistance
					closest = survivor
				}
			}
		}
	}
	return closest
}




// Returns array of all players (bots included)
// ----------------------------------------------------------------------------------------------------------------------------

function GetSurvivors(){
	local ent = null
	while (ent = Entities.FindByClassname(ent, "player")){
		if (ent.GetZombieType() == 9){
			yield ent
		}
	}
}


// Returns array of all survivors (bots excluded)
// ----------------------------------------------------------------------------------------------------------------------------

::GetHumanSurvivors <- function(){
	local ent = null
	while (ent = Entities.FindByClassname(ent, "player")){
		if (ent.GetZombieType() == 9 && !IsPlayerABot(ent)){
			yield ent
		}
	}
}




// Validates script scope and returns it
// ----------------------------------------------------------------------------------------------------------------------------

::GetValidatedScriptScope <- function(ent){
	ent.ValidateScriptScope()
	return ent.GetScriptScope()
}




// Precache survivor models so game wont crash due to the "cm_NoSurvivorBots = 1" bug...Valve please fix
// ----------------------------------------------------------------------------------------------------------------------------

function precacheSurvivorModels(){
	
	local path = "models/survivors/"
	local models =
	[
		"survivor_coach.mdl", "survivor_gambler.mdl", "survivor_manager.mdl", "survivor_mechanic.mdl",
		"survivor_namvet.mdl", "survivor_biker.mdl", "survivor_producer.mdl", "survivor_teenangst.mdl"
	]

	foreach(model in models){
		if (!IsModelPrecached( path + model)){
			PrecacheModel(path + model)
		}
	}
}




// Precache projectile models and mushroom
// ----------------------------------------------------------------------------------------------------------------------------

function precacheRocketDudeModels(){
	
	local models =
	[
		"models/props_collectables/mushrooms_glowing.mdl",
		"models/w_models/weapons/w_rd_grenade_scale_x4_burn.mdl",
		"models/w_models/weapons/w_rd_grenade_scale_x4.mdl"
	]
	
	foreach(model in models){
		if(!IsModelPrecached(model)){
			PrecacheModel(model)
		}
	}
}




// Check if the current map is a valve map
// ----------------------------------------------------------------------------------------------------------------------------

::IsValveMap <- function(){
	if (valveMaps.find(mapName) == null){
		return false
	}
	return true
}




// Array of maps c1 - c14
// ----------------------------------------------------------------------------------------------------------------------------

::valveMaps <- [
	// DEAD CENTER
	"c1m1_hotel"
	"c1m2_streets"
	"c1m3_mall"
	"c1m4_atrium"
	// DARK CARNIVAL
	"c2m1_highway"
	"c2m2_fairgrounds"
	"c2m3_coaster"
	"c2m4_barns"
	"c2m5_concert"
	// SWAMP FEVER
	"c3m1_plankcountry"
	"c3m2_swamp"
	"c3m3_shantytown"
	"c3m4_plantation"
	// HARD RAIN
	"c4m1_milltown_a"
	"c4m2_sugarmill_a"
	"c4m3_sugarmill_b"
	"c4m4_milltown_b"
	"c4m5_milltown_escape"
	// THE PARISH
	"c5m1_waterfront"
	"c5m1_waterfront_sndscape"
	"c5m2_park"
	"c5m3_cemetery"
	"c5m4_quarter"
	"c5m5_bridge"
	// THE PASSING
	"c6m1_riverbank"
	"c6m2_bedlam"
	"c6m3_port"
	// THE SACRIFICE
	"c7m1_docks"
	"c7m2_barge"
	"c7m3_port"
	// NO MERCY
	"c8m1_apartment"
	"c8m2_subway"
	"c8m3_sewers"
	"c8m4_interior"
	"c8m5_rooftop"
	// CRASH COURSE
	"c9m1_alleys"
	"c9m2_lots"
	// DEATH TOLL
	"c10m1_caves"
	"c10m2_drainage"
	"c10m3_ranchhouse"
	"c10m4_mainstreet"
	"c10m5_houseboat"
	// DEAD AIR
	"c11m1_greenhouse"
	"c11m2_offices"
	"c11m3_garage"
	"c11m4_terminal"
	"c11m5_runway"
	// BLOOD HARVEST
	"c12m1_hilltop"
	"c12m2_traintunnel"
	"c12m3_bridge"
	"c12m4_barn"
	"c12m5_cornfield"
	// COLD STREAM
	"c13m1_alpinecreek"
	"c13m2_southpinestream"
	"c13m3_memorialbridge"
	"c13m4_cutthroatcreek"
	// THE LAST STAND
	"c14m1_junkyard"
	"c14m2_lighthouse"
]




// Mushroom positions of maps ( c1 -14 )
// ----------------------------------------------------------------------------------------------------------------------------

::mushroomPositions <-
{
	c1m1_hotel =
	[
		{ origin = Vector(910.302,5475.81,2656.03), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(3430.85,7487.11,1664.03), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(2168.26,5703.24,2464.03), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2480.38,6217.6,2656.03), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(2311.68,7656.3,2464.03), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(1924.48,5762.97,1336.03), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(540.982,4832.06,1320.03), angles = "0 0 0", rotating = false, type = "large" }
	]
	c1m2_streets =
	[
		{ origin = Vector(1059.62,4854.1,704.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-6132.59,-1135.09,472.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-3897.52,2238.46,320.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-1253.71,777.393,811.381), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-5343.9,-2082.83,456.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-8619.01,-2111.07,963.138), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-7171.31,-4490.4,1224.7), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(1598.73,4225.02,521.433), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-2223.24,982.305,41.804), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-4588.86,1475.42,440.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-8635.88,-4498.73,440.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c1m3_mall =
	[
		{ origin = Vector(6447.99,-2648.58,288.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(1294.77,-2343.76,325.803), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(675.635,-4834.9,536.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(3600.03,-2384.03,825.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(4008.45,-290.606,0.03125), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(2266.34,-1561.81,536.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-198.189,-5201.84,415.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1891.39,-4127.36,574.433), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(6997.87,-1362.59,152.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(3896.59,-2873.28,318.958), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2754.07,-1866.65,280.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2414.66,-2412.11,536.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1584.63,-5446.67,364.031), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(-1239.21,-4472.65,318.958), angles = "0 0 0", rotating = false, type = "large" }
	]
	c1m4_atrium =
	[
		{ origin = Vector(-1806.74,-4825.39,621.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-2388.27,-3878.41,824.031), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(-3856.95,-3123.88,536.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-2572.11,-5303.06,553.52), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-6031.35,-3306.58,792.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-3340.16,-4001.26,744.781), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-5103.33,-3918.44,408.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-4451.52,-3207.95,106.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-3209.12,-3865.85,107.617), angles = "0 90 0", rotating = false, type = "large" }
		{ origin = Vector(-5343.23,-4186.55,1080.03), angles = "0 0 0", rotating = false, type = "large" }
	]
	c2m1_highway =
	[
		{ origin = Vector(9530.42,8430.98,-176.474), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(2273.79,4287.25,-936.719), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2188.58,3274.16,-807.969), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(3462.18,8450.17,-843.079), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1168.83,2091.84,-1738.7), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(6915.73,7505.84,-675.791), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(3015.77,6931.89,-899.608), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2914.95,4895.79,-507.969), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1163.45,2193.78,-1213.73), angles = "0 0 0", rotating = false, type = "large" }
		{ origin = Vector(-1334.14,-2035.05,-510.97), angles = "0 0 0", rotating = false, type = "large" }
	]
	c2m2_fairgrounds =
	[
		{ origin = Vector(3966.348633,-465.165253,48.42), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-1985.2,-3877.99,32.0313), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-3616.02,-721.635,0.03125), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1576.99,1513.79,8.03125), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-3329.16,-4239.81,352.595), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(2710.8,516.643,200.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-2126.08,318.905,128.031), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(-874.256,-1539.82,128.031), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(-1493.91,-4415.5,-1.77925), angles = "0 0 0", rotating = false, type = "large" }
	]
	c2m3_coaster =
	[
		{ origin = Vector(2048.36,3296.04,196.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-1582.4,1617.42,128.281), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-87.7301,3973.93,208.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2797.84,1638.93,-35.5456), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-3968.39,1550.79,413.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-66.8414,3611.93,208.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-2754.75,1143.2,620.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-3743.81,3732.83,544.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c2m4_barns =
	[
		{ origin = Vector(3138.24,3629.02,-3.96875), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-2756.8,1308.9,-43.9688), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(1081.55,1024.68,-147.969), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2166.15,1419.64,18.4938), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-226.231,886.084,387.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-1918.83,95.4541,32.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-3042.29,1694.38,-255.969), angles = "0 0 0", rotating = false, type = "large" }
		{ origin = Vector(3715.38,662.404,-191.969), angles = "0 0 0", rotating = false, type = "tiny" }
	]
	c2m5_concert =
	[
		{ origin = Vector(-1096.98,2354.9,-255.969), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-2308.02,3211.99,140.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-2637.91,3340.46,312.678), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-448.975,2760.9,-255.969), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1979.98,2505.26,191.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-2679.04,2500.67,191.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c3m1_plankcountry =
	[
		{ origin = Vector(-10586.4,10170.8,571.008), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-5590.18,6843.73,220.031), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(-980.031,4902.7,144.16), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-1067.97,4902.7,144.16), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-1022.58,4902.7,144.16), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-8121.03,7213.5,266.604), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-5392.27,5891.52,256.034), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(-6212.27,7861.63,48.0313), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-3386.78,6069.38,698.369), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(-2159.44,8640.77,253.1), angles = "0 0 0", rotating = false, type = "large" }
		{ origin = Vector(-1022.87,4946.13,332.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c3m2_swamp =
	[
		{ origin = Vector(-8114.13,5131.93,295.391), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-1801.48,2818.93,47.6229), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(-1884.05,3218.16,36.4844), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1936.43,1250.89,19.2292), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(7614.55,3192.79,122.329), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1895.61,3104.54,226.169), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(4779.86,1102.69,41.265), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(8702.53,512.321,569.088), angles = "0 0 0", rotating = false, type = "large" }
	]
	c3m3_shantytown =
	[
		{ origin = Vector(-5293.03,1199.51,871.913), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-4088.94,-3094.7,189.711), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(-659.526,-2485.02,4.4949), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-4605.58,-236.376,181.425), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(1532.24,-4869.25,24.0313), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-2651.48,-931.619,74.849), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-5504.8,-3256.66,308.68), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(3013.28,-4477.09,86.1035), angles = "0 90 0", rotating = false, type = "large" }
	]
	c3m4_plantation =
	[
		{ origin = Vector(-3650.61,-1527.09,542.849), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(1665.36,900.156,127.237), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(1788.93,-415.403,224.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2591.66,57.0649,224.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2032.64,252.058,416.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(1664.07,314.551,416.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1663.35,291.383,224.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1320.5,251.85,416.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2743.47,-3207.78,65.3052), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(3040.81,2016.1,133.507), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1426.21,-3443.73,187.907), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1665.04,536.081,640.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1867.68,-138.64,600.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c4m1_milltown_a =
	[
		{ origin = Vector(-5801.77,7494.31,1009.75), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(383.878,3381.04,368.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-6356.01,7456.24,104.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-1547.58,6908.92,200.773), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(4152.82,1222.7,184.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-609.475,6187.33,296.031), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(1482.28,4149.37,435.32), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(3617.5,2161.08,368.155), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(3338.04,179.84,586.974), angles = "0 0 0", rotating = false, type = "large" }
	]
	c4m2_sugarmill_a =
	[
		{ origin = Vector(4260,-3671.71,406.515), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-719.081,-7283.16,441.979), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-921.116,-8917.79,295.392), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2429.61,-5696.4,124.659), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(4315.07,-4528.41,97.6315), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-10.6827,-12670.2,113.272), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(3212.06,-3036.58,1164.28), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2725.17,-4272.82,329.469), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(2581.79,-6098.72,100.829), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-345.992,-8559.92,624.281), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(-1507.19,-13161,1141.23), angles = "0 0 0", rotating = false, type = "large" }
	]
	c4m3_sugarmill_b =
	[
		{ origin = Vector(-925.624,-13530.8,432.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-53.2867,-6479.09,441.729), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2434.5,-5315.34,194.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2587.19,-6096.47,100.157), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(4114.54,-3217.8,406.265), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1106.24,-8463.68,624.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(936.826,-6244.9,638.807), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(430.224,-4582.72,310.428), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1741.85,-3929.74,737.02), angles = "0 0 0", rotating = false, type = "large" }
	]
	c4m4_milltown_b =
	[
		{ origin = Vector(3331.17,-847.188,586.974), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(665.963,2783.55,227.927), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(387.227,3489.37,336.38), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(4327.79,1780.41,363.761), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(673.109,4776.85,131.802), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-1486.32,7441.23,366.277), angles = "0 0 0", rotating = false, type = "large" }
	]
	c4m5_milltown_escape =
	[
		{ origin = Vector(-5868.91,8159.17,348.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-4641.69,7626.45,479.597), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(-6338.14,7169.93,104.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-5432.06,7068.65,100.536), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-5315.37,8567.07,584.038), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-7088.42,7698.42,113.924), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(-5815.44,6623.25,126.972), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-5801.8,7496.52,1009.75), angles = "0 0 0", rotating = false, type = "large" }
	]
	c5m1_waterfront =
	[
		{ origin = Vector(-335.683,64.8597,-52.3949), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-1177.66,-2398.49,144.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-2347.78,-553.647,-367.969), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-2720.07,-1612.63,-13.3263), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-1904.66,-1864.33,-71.9454), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-3068.68,-2336.01,-157.992), angles = "0 0 0", rotating = false, type = "medium" }
	]
	c5m2_park =
	[
		{ origin = Vector(-5054.91,-2216.52,-127.982), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-9802.61,-5213.03,-79.9688), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-8046.08,-6670.04,-247.969), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-7940.64,-6671.62,-247.969), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-7551.83,-416.524,-127.969), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-7166.92,-3491.44,44.5587), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-8789.87,-5193.33,89.7595), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-8113.72,-5774.25,485.766), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-6815.91,-8437.09,250.906), angles = "0 0 0", rotating = false, type = "large" }
	]
	c5m3_cemetery =
	[
		{ origin = Vector(6127.99,7700.52,208.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(5907.05,1012.93,155.243), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2837.89,2634.4,176.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(4728.95,4570.35,131.378), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(4432.79,3202.69,154.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(6189.01,1337.86,-159.969), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(8768.77,-6591.84,756.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(7417.2,-8926.28,264.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c5m4_quarter =
	[
		{ origin = Vector(-2368.29,3616.46,64.0313), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-639.981,1607.46,224.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-569.655,1031.48,96.0313), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-3650.66,3888.94,384.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(29.7625,-1607.78,287.837), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-1193.22,1488.05,452.401), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-813.288,-2031.78,422.465), angles = "0 0 0", rotating = false, type = "large" }
	]
	c5m5_bridge =
	[
		{ origin = Vector(-6151.38,6420.53,765.699), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-1954.61,6463.8,852.885), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(2792.36,6336.46,790.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2792.36,6450.22,790.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2792.36,6211.1,790.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-7031.1,6298.27,456.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-12334.9,6552.2,453.565), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-3862.72,6225.25,897.47), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(2290.68,6425.58,790.031), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(14201,6326.86,790.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c6m1_riverbank =
	[
		{ origin = Vector(669.412,3116.3,640.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(1168,4459.88,510.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2095.14,1641.12,352.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(4520.78,2670.4,555.536), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(4461.7,2397.54,224.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-4004.19,554.621,864.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-4223.99,1571.49,727.091), angles = "0 0 0", rotating = false, type = "large" }
	]
	c6m2_bedlam =
	[
		{ origin = Vector(2148.07,-1201.23,288.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(1750.27,3709.59,-275.002), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(1498.32,4839.88,-159.969), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-224.862,1354.13,28.093), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(1213.93,1966.51,336.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(998.689,2701.23,96.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1589.86,4615.77,32.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(2868.05,5702.03,-1063.97), angles = "0 90 0", rotating = false, type = "large" }
		{ origin = Vector(5883.71,4207.33,-890.867), angles = "0 0 0", rotating = false, type = "large" }
	]
	c6m3_port =
	[
		{ origin = Vector(-2248.68,-646.404,320.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-1761.71,256.046,156.841), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(583.696,1765.25,160.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-1184.55,-952.523,0.03125), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-788.678,-952.523,0.03125), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-1379.67,-952.523,0.03125), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-374.426,-889.011,0.0760522), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(447.796,1824.08,160.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-901.026,2123.37,320.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(345.633,-358.962,184.031), angles = "0 0 0", rotating = false, type = "small" }
	]
	c7m1_docks =
	[
		{ origin = Vector(14063.8,2301.94,16.2378), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(10153.7,449.507,129.809), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(11410.8,-229.048,-63.9688), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(12001.8,-787.905,-35.1111), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(5208.64,552.395,382.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(4679.74,764.071,303.384), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2516.95,-188.518,138.451), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(3404.88,1676.66,336.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c7m2_barge =
	[
		{ origin = Vector(9920.64,608.323,322.374), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-3827.21,671.672,342.031), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(2140.39,1436.81,132.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(5435.93,755.192,256.282), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(10062.7,2095.96,305.796), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-593.486,2559.1,756.694), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-2894.79,725.009,576.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c7m3_port =
	[
		{ origin = Vector(1052.7,2623.67,544.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-2137.34,-539.338,-95.9688), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(680.945,2047.86,160.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(583.284,1770.19,160.758), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-938.757,931.624,352.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(736.739,2264.6,640.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(1560.46,168.305,345.56), angles = "0 90 0", rotating = false, type = "large" }
	]
	c8m1_apartment =
	[
		{ origin = Vector(1811.17,1797.96,640.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(896.289,3030.33,637.176), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2797.04,4191.32,15.8693), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(334.88,767.923,957.29), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(2624.62,2212.92,945.241), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(1976.26,3944.68,608.031), angles = "0 0 0", rotating = false, type = "large" }
		{ origin = Vector(3493.26,4004.85,1436.03), angles = "0 0 0", rotating = false, type = "tiny" }
	]
	c8m2_subway =
	[
		{ origin = Vector(2937.46,4155.97,-178.67), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(8467.56,3832.97,376.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(4526.2,3801.29,-287.969), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(2204.75,3968.89,-335.969), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(6775.15,2899.15,-178.67), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(7567.9,3417.3,424.031), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(8328.45,4596.1,1216.03), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(8805.87,5685.34,768.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c8m3_sewers =
	[
		{ origin = Vector(12631.2,5360.45,957.54), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(12712.9,6696.47,800.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(13137.6,7424.46,16.0313), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(11203.7,5091.59,712.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(11852.1,7923.79,276.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(13711,10120.7,-358.28), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(13068.6,10985.1,-191.969), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(13070.8,11448,-277.217), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(13788.6,11101.2,746.031), angles = "0 0 0", rotating = false, type = "large" }
		{ origin = Vector(13198.7,13927.2,5624.03), angles = "0 0 0", rotating = false, type = "large" }
	]
	c8m4_interior =
	[
		{ origin = Vector(12162.3,13317.7,42.4583), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(13687.1,14624.8,576.031), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(12718.3,14651.8,424.772), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(13695.3,13991.1,5641.54), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(12314.1,13388.4,152.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(13439.6,15006.3,624.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(14045.5,14862.1,5920.03), angles = "0 0 0", rotating = false, type = "large" }
	]
	c8m5_rooftop =
	[
		{ origin = Vector(7487.75,9322.88,6314.71), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(5986.62,7845.9,6210.03), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(7303.02,8911.17,6092.24), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(7048.08,9024.08,6096.03), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(6960.91,9464.52,5644.03), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(7022.35,7746.25,16.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(7714.38,9340.58,5952.03), angles = "0 0 0", rotating = false, type = "large" }
	]
	c9m1_alleys =
	[
		{ origin = Vector(-8671.74,-9921.56,384.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(205.191,-6577.32,-45.685), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-2334.43,-8371.1,0.03125), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-7876.03,-10448,192.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-6194.29,-10207.2,348.124), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(-2692.39,-9362.13,362.682), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-1326.74,-3292.39,445.932), angles = "0 0 0", rotating = false, type = "large" }
	]
	c9m2_lots =
	[
		{ origin = Vector(1621.53,-1232.15,186.989), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(6858.532,6943.091,223.031), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(7559.25,6343.99,48.0313), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(7559.25,6680.94,48.0313), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(7535.98,6160.13,427.767), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(3568.14,-492.286,35.807), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(1761.86,218.214,45.0175), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(7844.706,6643.726,375.036), angles = "0 90 0", rotating = false, type = "large" }
	]
	c10m1_caves =
	[
		{ origin = Vector(-11659.9,-13385.5,554.054), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-12974.9,-6724.85,176.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-12244.6,-5599.09,-73.601), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-13089.6,-5241.27,-287.969), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-12349.5,-9805.34,496.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-12974.9,-5860.65,176.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-10690.6,-4991.48,688.028), angles = "0 90 0", rotating = false, type = "large" }
	]
	c10m2_drainage =
	[
		{ origin = Vector(-11215.6,-8447.19,-273.116), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-8220.77,-8322.58,-452.1), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-9873.86,-7689.84,-376.396), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-10213.5,-8154.52,-162.483), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-9872.4,-6733.67,-307.969), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-7846.5,-6987.36,-457.214), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-8826.14,-7633.1,953.457), angles = "0 0 0", rotating = false, type = "large" }
	]
	c10m3_ranchhouse =
	[
		{ origin = Vector(-9839.35,-6342.99,89.6114), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-4811.54,-1131.53,506.244), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-9440.1,-2750.96,-38.9688), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-6958,-1886.3,8.03125), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-8059.92,-5811.83,400.031), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-12539.413,-6515.756,408.296), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-9092.79,-3946.72,356.642), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-5081.95,-1693.59,626.119), angles = "0 0 0", rotating = false, type = "large" }
	]
	c10m4_mainstreet =
	[
		{ origin = Vector(-3068.25,-57.6381,1039.03), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(2790.76,-1699.64,336.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-1375.73,-4670.05,-55.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-1425.11,-4670.65,-55.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(137.127,-1897.99,112.031), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(2756.35,-2412.78,336.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(1617.19,-4384.35,96.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-673.274,-4583.52,176.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-1399.49,-4674.15,192.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c10m5_houseboat =
	[
		{ origin = Vector(2123.12,2634.09,326.222), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(4225.13,-5089.24,-170.896), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(2874.1,2413.57,-39.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(3065.88,2759.15,-39.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(3952.22,256.841,324.537), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(3854.66,4218.71,320.031), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(4264.85,-4686.83,231.018), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(2195.19,-4720.26,-35.1493), angles = "0 0 0", rotating = false, type = "large" }
	]
	c11m1_greenhouse =
	[
		{ origin = Vector(6418.19,-690.905,831.396), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(3427.550,1374.021,819.144), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(3518.21,2217.03,183.338), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(3370.21,731.601,554.228), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(2910.57,2108.9,416.535), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(4351.72,-300.349,1116.8), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(3394.22,-871.949,1029.47), angles = "0 0 0", rotating = false, type = "large" }
	]
	c11m2_offices =
	[
		{ origin = Vector(5488.19,4064.33,434.733), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(7419.72,3330.88,1212.23), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(7513.56,5654.95,16.0313), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(5839.04,3168.24,523.664), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(6272.13,1022.59,16.0313), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(5447.53,3558.41,303.983), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(6623.48,4828.47,600.482), angles = "0 0 0", rotating = false, type = "large" }
	]
	c11m3_garage =
	[
		{ origin = Vector(-3838.76,-3139.08,936.54), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-5872.75,-1719.78,512.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-3488.1,2854.93,32.0313), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-3647.99,2854.92,31.0313), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-3565.8,2854.83,32.0313), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-4952.03,-2623.2,352.031), angles = "0 90 0", rotating = false, type = "tiny" }
		{ origin = Vector(-6805.34,-1273.95,550.072), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-5239.47,124.543,1301.27), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-2881.81,3153.91,160.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c11m4_terminal =
	[
		{ origin = Vector(-93.3845,4457.05,144.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(98.4939,3620.52,16.0313), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(1163.08,4456.62,296.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(710.154,5631.1,296.031), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(541.737,3785.52,536.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(471.801,2959.14,348.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(2130.92,1586.85,448.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(2780.61,6941.86,313.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c11m5_runway =
	[
		{ origin = Vector(-6838.83,9651.14,568.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-5431.83,11812.2,62.8417), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-5418.15,10341.3,60.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-6900.6,11531.3,-191.969), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-6891.96,10827.7,-191.969), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-5795.82,9010.43,176.974), angles = "0 0 0", rotating = false, type = "large" }
	]
	c12m1_hilltop =
	[
		{ origin = Vector(-8089.921,-15117.432,277.785), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-6446.82,-8719.63,1015.15), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-6553.63,-7570.19,384.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-6418.22,-7523.43,365.19), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-6367.87,-7414.88,377.974), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-10427.594,-13344.635,746.753), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-10980.1,-10901.5,938.975), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-8990.35,-8981.87,1062.03), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-7808.35,-9486.53,992.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c12m2_traintunnel =
	[
		{ origin = Vector(-8229.1,-7517.71,160.353), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-7719.68,-8901.63,304.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-4604.06,-8322.47,-63.5097), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-4175.46,-8323.85,-63.9688), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-3711.27,-8392.14,-63.1514), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-8740.09,-7214.79,200.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-8547.49,-8900.32,304.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-7563.7,-8612.52,826.025), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-4185.79,-8717.72,232.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c12m3_bridge =
	[
		{ origin = Vector(-1137.81,-10944.3,160.031), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(1827.29,-12229.5,484.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(1913.03,-12602.3,-31.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(2030.97,-12602.3,-31.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1970.48,-12602.3,-31.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-952.414,-10439.4,72.0312), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(3342.01,-14299.5,169.088), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(4914.05,-13113.9,1141.33), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(5932.44,-13851.9,272.05), angles = "0 0 0", rotating = false, type = "large" }
	]
	c12m4_barn =
	[
		{ origin = Vector(9334.13,-9355.23,932.537), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(11022.1,-4584.55,324.481), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(10382,-2600.35,-63.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(10526,-2600.35,-63.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(10453.7,-2600.35,-63.9688), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(7488.13,-10687,897.565), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(10616.6,-7429.15,274.641), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(9688.78,-4243.98,722.381), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(10453.7,-1712.4,268.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c12m5_cornfield =
	[
		{ origin = Vector(10059.6,821.12,462.47), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(7138.16,270.204,596.031), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(8960.78,3370.82,201.741), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(9060.78,3370.82,204.697), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(9272.22,3547.45,961.057), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(8446.37,422.173,590.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(6823.95,1191.26,794.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(7186.65,2650.19,1034.12), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(7536.12,2649.97,1034.12), angles = "0 0 0", rotating = false, type = "large" }
	]
	c13m1_alpinecreek =
	[
		{ origin = Vector(-2778.1,1140.71,255.406), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(1200.27,1406.95,1601.38), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(992.23,183.899,585.485), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(1120.63,183.726,585.398), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-2876.72,2797.21,1273), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-2332,3247.16,976.031), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(869.342,2451.07,805.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(880.042,-464,476.011), angles = "0 90 0", rotating = false, type = "large" }
	]
	c13m2_southpinestream =
	[
		{ origin = Vector(7961.18,6390.28,585.92), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(6728,2925.41,1216.03), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(78.6595,8679.27,-404.969), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(8107.63,4172.91,649.555), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(5677.56,2211.83,1090), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(4905.09,2577.37,1120.03), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-356.712,4977.07,272.031), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-348.279,6151.25,302.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c13m3_memorialbridge =
	[
		{ origin = Vector(-2169.22,-4092.02,1758.03), angles = "0 90 0", rotating = true, type = "bh" }
		{ origin = Vector(-2169.54,-4092.02,2201.03), angles = "0 90 0", rotating = false, type = "item" }
		{ origin = Vector(1003.74,-4472.38,590.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-3844.47,-4095.34,896.031), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(6777.83,-4114.74,2201.03), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(3687.47,-4074.24,2201.03), angles = "0 90 0", rotating = false, type = "medium" }
		{ origin = Vector(3686.79,-4095.17,896.031), angles = "0 90 0", rotating = false, type = "large" }
	]
	c13m4_cutthroatcreek =
	[
		{ origin = Vector(-3872.6,-8143.45,723.031), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-772.295,3198.8,-101.969), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-1174.01,4688.39,180.031), angles = "0 0 0", rotating = false, type = "exp" }
		{ origin = Vector(-3622.38,-5926.86,623.746), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-3916.44,-3227.55,360.898), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-653.084,1568.25,18.0313), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-391.136,3752.91,88.0313), angles = "0 0 0", rotating = false, type = "large" }
	]
	c14m1_junkyard =
	[
		{ origin = Vector(-4227.94,-8819.65,103), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-2505.24,1649.99,182.772), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(-4450.59,2204.69,-58.7463), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-1669.74,-5730.32,-300.582), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(-2676.9,2190.81,-50.752), angles = "0 0 0", rotating = false, type = "small" }
		{ origin = Vector(-4814.390,2711.914,100.450), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-2407,7408.93,168.031), angles = "0 0 0", rotating = false, type = "large" }
	]
	c14m2_lighthouse =
	[
		{ origin = Vector(1319.83,344.463,830.588), angles = "0 0 0", rotating = true, type = "bh" }
		{ origin = Vector(-2479.24,5569.72,-101.291), angles = "0 0 0", rotating = false, type = "item" }
		{ origin = Vector(320.403,923.429,560.905), angles = "0 90 0", rotating = false, type = "exp" }
		{ origin = Vector(-4567.81,3575.97,1400.03), angles = "0 0 0", rotating = false, type = "tiny" }
		{ origin = Vector(479.378,946.381,696.031), angles = "0 90 0", rotating = false, type = "small" }
		{ origin = Vector(-981.672,2524.87,701.112), angles = "0 0 0", rotating = false, type = "medium" }
		{ origin = Vector(-4725,5825,-92.968), angles = "0 0 0", rotating = false, type = "large" }
	]
}




// Output count of mushroom statistics
// ----------------------------------------------------------------------------------------------------------------------------

::map_mushroom_stats <- {}

::outputMushroomData <- function(){
	
	map_mushroom_stats.clear()
	local count_total = 0
	local nl = "\n"
	
	foreach(mapname, mushroomArray in mushroomPositions){
		foreach(DS in mushroomArray){
			local type = DS.type
			if(!(mapname in map_mushroom_stats)){
				map_mushroom_stats[mapname] <- { bh = 0, exp = 0, item = 0, tiny = 0, small = 0, medium = 0, large = 0 }
			}
			map_mushroom_stats[mapname][type] += 1
			count_total += 1
		}
	}
	
	printl("- - - - Mushroom stats - - - -" + nl)
	//
	printl("Total count of placed mushrooms: " + count_total + " ( " + mushroomPositions[mapName].len() + " in this map )" + nl)
	//
	foreach(mapname, datatable in map_mushroom_stats){
		printl("================== " + mapname + " " + GetCharChain("=", 32 - mapname.len() ) + nl)
		printl("BunnyHop: " + datatable.bh + "  Explosive: " + datatable.exp + "  Item: " + datatable.item)
		printl("Tiny: " + datatable.tiny + "  Small: " + datatable.small + "  Medium: " + datatable.medium + "  Large: " + datatable.large + nl)
	}
}




// Returns a concatenated string of the passed string with length of num
// ----------------------------------------------------------------------------------------------------------------------------

::GetCharChain <- function(str, num){
	local txt = ""
	for(local i = 0; i < num; i++){
		txt += str
	}
	return txt
}




// Returns the slot the weapon belongs to
// ----------------------------------------------------------------------------------------------------------------------------

function getItemSlot(item){
	local className = item.GetClassname()
	
	local slot0 =
	[
		"weapon_grenade_launcher","weapon_rifle_m60",
		"weapon_rifle","weapon_rifle_desert","weapon_rifle_ak47",
		"weapon_rifle_sg552","weapon_smg_mp5",
		"weapon_shotgun_chrome","weapon_pumpshotgun",
		"weapon_shotgun_spas","weapon_autoshotgun",
		"weapon_smg","weapon_smg_silenced",
		"weapon_hunting_rifle","weapon_sniper_military",
		"weapon_sniper_scout","weapon_sniper_awp"
	]
	local slot1 = 
	[
		"weapon_melee","weapon_chainsaw",
		"weapon_pistol","weapon_pistol_magnum"
	]
	local slot2 =
	[
		"weapon_molotov","weapon_pipe_bomb","weapon_vomitjar"
	]
	local slot3 =
	[
		"weapon_first_aid_kit","weapon_defibrillator",
		"weapon_upgradepack_explosive","weapon_upgradepack_incendiary"
	]
	local slot4 =
	[
		"weapon_adrenaline","weapon_pain_pills"
	]
	local slot5 = 
	[
		"weapon_oxygentank","weapon_propanetank","weapon_gascan",
		"weapon_gnome","weapon_cola_bottles","weapon_fireworkcrate"
	]

	if(slot0.find(className) != null){
		return "slot0"
	}else if(slot1.find(className) != null){
		return "slot1"
	}else if(slot2.find(className) != null){
		return "slot2"
	}else if(slot3.find(className) != null){
		return "slot3"
	}else if(slot4.find(className) != null){
		return "slot4"
	}else if(slot5.find(className) != null){
		return "slot5"
	}else{
		return null
	}
}




// This will track timings of the survivor
// ----------------------------------------------------------------------------------------------------------------------------

::PlayerTimeData <- {}

function PlayerTimer(ent){

	if(!(ent in PlayerTimeData)){
		PlayerTimeData[ent] <- { timerActive = false, finished = false, startTime = Time(), endTime = Time(), time_best = 0, ticks = 0, seconds = 0 }
	}
	
	if(PlayerIsOnGround(ent)){
		if(ent in PlayerTimeData){
			if(!PlayerTimeData[ent].finished){
				if(PlayerTimeData[ent].ticks < 30){
					PlayerTimeData[ent].ticks += 1
				}else{
					PlayerTimeData[ent].ticks = 0
					PlayerTimeData[ent].seconds += 1
				}
			}
		}
	}
}




// Check if survivor reached the saferoom
// ----------------------------------------------------------------------------------------------------------------------------

function survivorSaferoomCheck(ent){
	if(!PlayerTimeData[ent].finished){
		if( ResponseCriteria.GetValue(ent, "incheckpoint" ) == "1" ){
			printFinalGroundTime(ent)
			ProcessSurvivorTime(ent)
		}
	}
}




// Iteration over all human player and pass them to different methods
// ----------------------------------------------------------------------------------------------------------------------------

function PlayerFunctions(){
	foreach(ent in GetHumanSurvivors()){
		if(ent.IsValid()){
			PlayerTimer(ent)
			survivorSaferoomCheck(ent)
		}
	}
}




// Returns true when player is on the ground
// ----------------------------------------------------------------------------------------------------------------------------

function PlayerIsOnGround(player){
	if(NetProps.GetPropInt(player, "m_fFlags") & 1){
		return true
	}
	return false
}




// Print a chat message in color x 
// ----------------------------------------------------------------------------------------------------------------------------

function toChat(color, message, sound){
	local player = Entities.FindByClassname(null, "player")
	switch(color)
	{
		case "white"	: color = "\x01" ; break
		case "blue"		: color = "\x03" ; break
		case "orange"	: color = "\x04" ; break
		case "green"	: color = "\x05" ; break
	}
	switch(sound)
	{
		case "reward"	: sound = "ui/littlereward.wav" ; break
		case "error"	: sound = "ui/beep_error01.wav" ; break
		case "click"	: sound = "ui/menu_click01.wav" ; break
	}
	ClientPrint(null, 5, color + message)
	if(sound != null){
		EmitAmbientSoundOn( sound, 1, 100, 100, player)
	}
}




// Will change the model of "tank_rock" to a log when it is a L4D1 map
// When "last chance mode" is active, the rock will start glowing
// ----------------------------------------------------------------------------------------------------------------------------

function tankrockListener(){
	local rock = null

	while(rock = Entities.FindByClassname(rock, "tank_rock")){
		if(rock.IsValid()){
			local scope = GetValidatedScriptScope(rock)
			
			if(survivorSet == 1){
				if(!("usesLog" in scope)){
					rock.SetModel("models/props_foliage/tree_trunk.mdl")
					scope["usesLog"] <- true
				}
			}
			
			// When last change mode is active we need to enable the glow on all new rocks
			if(last_chance_active){
				if(!("glowing" in scope)){
					NetProps.SetPropInt(rock, "m_Glow.m_iGlowType", 3)
					rock.GetScriptScope()["glowing"] <- true
				}
			}
		}
	}
}




// Returns the given color with changed intesity as string 
// ----------------------------------------------------------------------------------------------------------------------------

function getColorWithIntensity(color, intensity){	

	local values = split(color, " ")
	
	local rNew = values[0].tofloat()
	local gNew = values[1].tofloat()
	local bNew = values[2].tofloat()

	rNew	= (rNew / 100 * intensity).tointeger()
	gNew	= (gNew / 100 * intensity).tointeger()
	bNew	= (bNew / 100 * intensity).tointeger()

	return "" + rNew + " " + gNew + " " + bNew
}




// Is the current server a local one
// ----------------------------------------------------------------------------------------------------------------------------

function OnLocalServer(){
	if(GetListenServerHost() == null){
		return false
	}
	return true
}

Community Mutations

These mutations were made by the community, eventually added to the base game by valve.

Community1 - Special Delivery

 
//-----------------------------------------------------
Msg("Activating Special Delivery\n");
Msg("Made by Rayman1103\n");

if ( !IsModelPrecached( "models/infected/smoker.mdl" ) )
	PrecacheModel( "models/infected/smoker.mdl" );
if ( !IsModelPrecached( "models/infected/smoker_l4d1.mdl" ) )
	PrecacheModel( "models/infected/smoker_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/boomer.mdl" ) )
	PrecacheModel( "models/infected/boomer.mdl" );
if ( !IsModelPrecached( "models/infected/boomer_l4d1.mdl" ) )
	PrecacheModel( "models/infected/boomer_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/boomette.mdl" ) )
	PrecacheModel( "models/infected/boomette.mdl" );
if ( !IsModelPrecached( "models/infected/hunter.mdl" ) )
	PrecacheModel( "models/infected/hunter.mdl" );
if ( !IsModelPrecached( "models/infected/hunter_l4d1.mdl" ) )
	PrecacheModel( "models/infected/hunter_l4d1.mdl" );
if ( !IsModelPrecached( "models/infected/limbs/exploded_boomette.mdl" ) )
{
	PrecacheModel( "models/infected/limbs/exploded_boomette.mdl" );
	::community1_no_female_boomers <- true;
}
if ( !IsModelPrecached( "models/infected/spitter.mdl" ) )
	PrecacheModel( "models/infected/spitter.mdl" );
if ( !IsModelPrecached( "models/infected/jockey.mdl" ) )
	PrecacheModel( "models/infected/jockey.mdl" );
if ( !IsModelPrecached( "models/infected/charger.mdl" ) )
	PrecacheModel( "models/infected/charger.mdl" );

MutationOptions <-
{
	ActiveChallenge = 1

	cm_CommonLimit = 0
	cm_DominatorLimit = 8
	cm_MaxSpecials = 8
	cm_ProhibitBosses = false
	cm_SpecialRespawnInterval = 0
	cm_AggressiveSpecials = false

	SpecialInitialSpawnDelayMin = 0
	SpecialInitialSpawnDelayMax = 5
	ShouldAllowSpecialsWithTank = true
	EscapeSpawnTanks = true
	MobMinSize = 0
	MobMaxSize = 0
	NoMobSpawns = true

	SmokerLimit = 2
	BoomerLimit = 2
	HunterLimit = 2
	SpitterLimit = 2
	JockeyLimit = 2
	ChargerLimit = 2

	// convert items that aren't useful
	weaponsToConvert =
	{
		weapon_pipe_bomb =	"weapon_molotov_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}
	
	DefaultItems =
	[
		"weapon_pistol_magnum",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}
}

MutationState <-
{
	SIModelsBase = [ [ "models/infected/smoker.mdl", "models/infected/smoker_l4d1.mdl" ],
					[ "models/infected/boomer.mdl", "models/infected/boomer_l4d1.mdl", "models/infected/boomette.mdl" ],
						[ "models/infected/hunter.mdl", "models/infected/hunter_l4d1.mdl" ],
							[ "models/infected/spitter.mdl" ],
								[ "models/infected/jockey.mdl" ],
									[ "models/infected/charger.mdl" ] ]
	SIModels = [ [ "models/infected/smoker.mdl", "models/infected/smoker_l4d1.mdl" ],
				[ "models/infected/boomer.mdl", "models/infected/boomer_l4d1.mdl", "models/infected/boomette.mdl" ],
					[ "models/infected/hunter.mdl", "models/infected/hunter_l4d1.mdl" ],
						[ "models/infected/spitter.mdl" ],
							[ "models/infected/jockey.mdl" ],
								[ "models/infected/charger.mdl" ] ]
	ModelCheck = [ false, false, false, false, false, false ]
	LastBoomerModel = ""
	BoomersChecked = 0
	LeftSafeAreaThink = false
}

function LeftSafeAreaThink()
{
	local player = null;
	while ( player = Entities.FindByClassname( player, "player" ) )
	{
		if ( ( !player.IsValid() ) || ( NetProps.GetPropInt( player, "m_iTeamNum" ) != 2 ) )
			continue;
		
		if ( ResponseCriteria.GetValue( player, "instartarea" ) == "0" )
		{
			SessionOptions.cm_MaxSpecials = 8;
			SessionState.LeftSafeAreaThink = false;
			break;
		}
		else
			continue;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	local spawner = null;
	while ( spawner = Entities.FindByClassname( spawner, "info_zombie_spawn" ) )
	{
		if ( spawner.IsValid() )
		{
			local population = NetProps.GetPropString( spawner, "m_szPopulation" );
			
			if ( population == "boomer" || population == "hunter" || population == "smoker" || population == "jockey"
				|| population == "charger" || population == "spitter" || population == "new_special" || population == "church"
					|| population == "tank" || population == "witch" || population == "witch_bride" || population == "river_docks_trap" )
				continue;
			else
				spawner.Kill();
		}
	}
	
	if ( Director.GetMapName() == "c1m1_hotel" )
		DirectorOptions.cm_TankLimit <- 0;
	else if ( Director.GetMapName() == "c5m5_bridge" || Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 0;
	else if ( Director.GetMapName() == "c7m1_docks" )
		DirectorOptions.cm_ProhibitBosses = true;
}

function OnGameEvent_player_left_safe_area( params )
{
	local player = GetPlayerFromUserID( params["userid"] );
	if ( !player )
		return;
	
	local instartarea = ResponseCriteria.GetValue( player, "instartarea" );
	if ( instartarea == "1" )
	{
		SessionOptions.cm_MaxSpecials = 0;
		SessionState.LeftSafeAreaThink = true;
	}
}

function OnGameEvent_triggered_car_alarm( params )
{
	if ( !Director.IsTankInPlay() )
	{
		DirectorOptions.cm_AggressiveSpecials = true;
		ZSpawn( { type = 8 } );
		DirectorOptions.cm_AggressiveSpecials = false;
	}
	
	StartAssault();
}

function OnGameEvent_finale_start( params )
{
	if ( Director.GetMapName() == "c6m3_port" )
		DirectorOptions.cm_MaxSpecials = 8;
}

function OnGameEvent_gauntlet_finale_start( params )
{
	if ( Director.GetMapName() == "c5m5_bridge" )
		DirectorOptions.cm_MaxSpecials = 8;
}

function OnGameEvent_player_spawn( params )
{
	local player = GetPlayerFromUserID( params["userid"] );
	
	if ( ( !player ) || ( player.IsSurvivor() ) )
		return;
	
	local zombieType = player.GetZombieType();
	if ( zombieType > 6 )
		return;
	
	local modelName = player.GetModelName();
	
	if ( !SessionState.ModelCheck[ zombieType - 1 ] )
	{
		if ( (zombieType == 2) && !("community1_no_female_boomers" in getroottable()) )
		{
			if ( SessionState.LastBoomerModel != modelName )
			{
				SessionState.LastBoomerModel = modelName;
				SessionState.BoomersChecked++;
			}
			if ( SessionState.BoomersChecked > 1 )
				SessionState.ModelCheck[ zombieType - 1 ] = true;
		}
		else
			SessionState.ModelCheck[ zombieType - 1 ] = true;
		
		if ( SessionState.SIModelsBase[zombieType - 1].find( modelName ) == null )
		{
			SessionState.SIModelsBase[zombieType - 1].append( modelName );
			SessionState.SIModels[zombieType - 1].append( modelName );
		}
	}
	
	if ( SessionState.SIModelsBase[zombieType - 1].len() == 1 )
		return;
	
	local zombieModels = SessionState.SIModels[zombieType - 1];
	if ( zombieModels.len() == 0 )
		SessionState.SIModels[zombieType - 1].extend( SessionState.SIModelsBase[zombieType - 1] );
	local foundModel = zombieModels.find( modelName );
	if ( foundModel != null )
	{
		zombieModels.remove( foundModel );
		return;
	}
	
	local randomElement = RandomInt( 0, zombieModels.len() - 1 );
	local randomModel = zombieModels[ randomElement ];
	zombieModels.remove( randomElement );
	
	player.SetModel( randomModel );
}

function Update()
{
	if ( SessionState.LeftSafeAreaThink )
		LeftSafeAreaThink();
	if ( Director.GetCommonInfectedCount() > 0 )
	{
		local infected = null;
		while ( infected = Entities.FindByClassname( infected, "infected" ) )
		{
			if ( infected.IsValid() )
				infected.Kill();
		}
	}
}

Community2 - Flu Season

 
Msg("Activating Community Mutation 2\n");

DirectorOptions <-
{
	ActiveChallenge = 1
	RelaxMinInterval = 5
	RelaxMaxInterval = 10
	cm_SpecialRespawnInterval = 8
	SpecialInitialSpawnDelayMin = 1
	SpecialInitialSpawnDelayMax = 5

	cm_MaxSpecials = 8
	BoomerLimit = 4
	SpitterLimit = 4
	SmokerLimit = 0
	HunterLimit = 0
	ChargerLimit = 0
	JockeyLimit = 0

	ProhibitBosses = 1 //tanks still spawn at finales though
	MegaMobSize = 0

	// convert items that aren't useful
	weaponsToConvert =
	{
		weapon_vomitjar = 	"weapon_molotov_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}
}

function OnGameEvent_round_start_post_nav( params )
{
	local spawner = null;
	while ( spawner = Entities.FindByClassname( spawner, "info_zombie_spawn" ) )
	{
		if ( spawner.IsValid() )
		{
			local population = NetProps.GetPropString( spawner, "m_szPopulation" );
			
			if ( population == "boomer" || population == "spitter" || population == "church" || population == "river_docks_trap" )
				continue;
			else
				spawner.Kill();
		}
	}
}

Community3 - Riding My Survivor

 
Msg("Activating community mutation 3.\n");

DirectorOptions <-
{
	ActiveChallenge = 1
	
	cm_CommonLimit = 0
	
	BoomerLimit = 0
	ChargerLimit = 0
	HunterLimit = 0
	JockeyLimit = 4
	SmokerLimit = 0
	SpitterLimit = 0
	cm_MaxSpecials = 4
	
	cm_SpecialRespawnInterval = 20
	
	function ConvertZombieClass(id)
	{
		return 5;
	}
}

Community4 - Nightmare

 
//-----------------------------------------------------
Msg("Activating Nightmare\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_DominatorLimit = 8
	cm_MaxSpecials = 8
	cm_SpecialRespawnInterval = 30
	cm_AutoReviveFromSpecialIncap = 1
	cm_AllowPillConversion = 0
	cm_TankLimit = 4
	ProhibitBosses = 0

	BoomerLimit = 0
	SurvivorMaxIncapacitatedCount = 3
	SpecialInitialSpawnDelayMin = 5
	SpecialInitialSpawnDelayMax = 30
	TankHitDamageModifierCoop = 0.25	
}

Community5 - Death's Door

 
//-----------------------------------------------------
Msg("Activating Death's Door\n");
Msg("Made by Rayman1103\n");


DirectorOptions <-
{
	ActiveChallenge = 1

	cm_ShouldHurry = 1
	cm_AllowPillConversion = 0
	cm_AllowSurvivorRescue = 0
	SurvivorMaxIncapacitatedCount = 0

	weaponsToConvert =
	{
		weapon_first_aid_kit =	"weapon_pain_pills_spawn"
		weapon_adrenaline =	"weapon_pain_pills_spawn"
	}

	function ConvertWeaponSpawn( classname )
	{
		if ( classname in weaponsToConvert )
		{
			return weaponsToConvert[classname];
		}
		return 0;
	}

	DefaultItems =
	[
		"weapon_pistol",
		"weapon_pistol",
	]

	function GetDefaultItem( idx )
	{
		if ( idx < DefaultItems.len() )
		{
			return DefaultItems[idx];
		}
		return 0;
	}

	TempHealthDecayRate = 0.001
	function RecalculateHealthDecay()
	{
		if ( Director.HasAnySurvivorLeftSafeArea() )
		{
			TempHealthDecayRate = 0.27 // pain_pills_decay_rate default
		}
	}
}

function Update()
{
	DirectorOptions.RecalculateHealthDecay();
}

Community6 - Confogl

 
// vim: set ts=4
// CompLite.nut (Confogl Mutation)
// Copyright (C) 2012 ProdigySim
// All rights reserved.
// =============================================================================

IncludeScript("globals", this);

CompLite = InitializeCompLite();

// Don't need to do anything else if we're not first load
if(CompLite.Globals.GetCurrentRound() > 0)
{
	Msg("CompLite Starting Round "+CompLite.Globals.GetCurrentRound()+" on ");
	local mi = CompLite.Globals.MapInfo;
	if(mi.isIntro) Msg("an intro map.\n");
	else Msg("a non-intro map.\n");

	Msg("Found "+mi.saferoomPoints.len()+" saferoom points.\n");
	Msg("Map has a scavenge event? " + mi.hasScavengeEvent + "\n");
	Msg("MapName: "+mi.mapname+"\n");

	return;
}

Msg("Activating Mutation CompLite v3.6\n");

DirectorOptions.ActiveChallenge <- 1
DirectorOptions.cm_ProhibitBosses <- 0
DirectorOptions.cm_AllowPillConversion <- 0

// Name shortening references
local g_Timer = CompLite.Globals.Timer;
local g_FrameTimer = CompLite.Globals.FrameTimer;
local g_MapInfo = CompLite.Globals.MapInfo;
local g_GSC = CompLite.Globals.GSC;
local g_GSM = CompLite.Globals.GSM;
local g_MobResetti = CompLite.Globals.MobResetti;
local Modules = CompLite.Modules;

// Uncomment to add a debug event listener
//g_GSC.AddListener(Modules.MsgGSL());

g_GSC.AddListener(Modules.SpitterControl(Director, DirectorOptions, Entities));
g_GSC.AddListener(Modules.MobControl(g_MobResetti));


// Give out hunting rifles on non-intro maps.
// But limit them to 1 of each.
g_GSC.AddListener(Modules.HRControl(Entities, CompLite.Globals, Director));


g_GSC.AddListener(
	Modules.BasicItemSystems(
		// AllowWeaponSpawn Limits
		// 0: Always remove
		// >0: Keep the first n instances, delete others
		// <-1: Delete the first n instances, keep others.
		{
			weapon_defibrillator = 0
			weapon_grenade_launcher = 0
			weapon_upgradepack_incendiary = 0
			weapon_upgradepack_explosive = 0
			weapon_chainsaw = 0
			//weapon_molotov = 1
			//weapon_pipe_bomb = 2
			//weapon_vomitjar = 1
			weapon_propanetank = 0
			weapon_oxygentank = 0
			weapon_rifle_m60 = 0
			//weapon_first_aid_kit = -5
			upgrade_item = 0
		},
		// Conversion Rules
		{
		weapon_autoshotgun	  = "weapon_pumpshotgun_spawn"
		weapon_shotgun_spas	 = "weapon_shotgun_chrome_spawn"
		weapon_rifle			= "weapon_smg_spawn"
		weapon_rifle_desert	 = "weapon_smg_spawn"
		weapon_rifle_sg552	  = "weapon_smg_mp5_spawn"
		weapon_rifle_ak47	   = "weapon_smg_silenced_spawn"
		weapon_hunting_rifle	= "weapon_smg_silenced_spawn"
		weapon_sniper_military  = "weapon_shotgun_chrome_spawn"
		weapon_sniper_awp	   = "weapon_shotgun_chrome_spawn"
		weapon_sniper_scout	 = "weapon_pumpshotgun_spawn"
		weapon_first_aid_kit	= "weapon_pain_pills_spawn"
		weapon_molotov = "weapon_molotov_spawn"
		weapon_pipe_bomb = "weapon_pipe_bomb_spawn"
		weapon_vomitjar = "weapon_vomitjar_spawn"
		},
		// Default item list
		[
			"weapon_pain_pills",
			"weapon_pistol",
			"weapon_hunting_rifle"
		]
	)
);

// Enforce various item spawns to be single pickup.
g_GSC.AddListener(
	Modules.EntKVEnforcer(Entities,
		// classnames
		[
			"weapon_adrenaline_spawn",
			"weapon_pain_pills_spawn",
			"weapon_melee_spawn",
			"weapon_molotov_spawn",
			"weapon_vomitjar_spawn",
			"weapon_pipebomb_spawn"
		],
		// models
		[],
		// key to enforce
		"count",
		// value to set it to
		1
	)
);

// Entity tracking/removal/limiting
g_GSC.AddListener(
	Modules.ItemControl(Entities, 
	// Limit to value by classname
		{
			weapon_adrenaline_spawn = 1
			weapon_pain_pills_spawn = 4
			witch = 1
			func_playerinfected_clip = 0
			weapon_molotov_spawn = 1
			weapon_pipe_bomb_spawn = 1
			weapon_vomitjar_spawn = 1
		},
	// Limit to value by model name
		{
			["models/props_junk/propanecanister001a.mdl"] = 0,
			["models/props_equipment/oxygentank01.mdl"] = 0,
			["models/props_junk/explosive_box001.mdl"] = 1
		},
	// Remove these items from all saferooms
		[
			"weapon_adrenaline_spawn",
			"weapon_pain_pills_spawn",
			//"weapon_melee_spawn",
			"weapon_molotov_spawn",
			"weapon_pipe_bomb_spawn",
			"weapon_vomitjar_spawn"
		],
		g_MapInfo
	)
);

// Limit melee weapons to 4
g_GSC.AddListener(Modules.MeleeWeaponControl(Entities, 4));

// Remove all gascans on non-scavenge maps
g_GSC.AddListener(Modules.GasCanControl(Entities, g_MapInfo));


Msg("GSC/M/L Script run.\n");

Confogl Additional Scripts

These scripts are included in the main Confogl and globals scripts.

globals
 
// Call this once on script start to initialize CompLite's libraries and hook them up to ChallengeScript events.
// parentTable: The parent table where the CompLite library namespace should be created. This 
//		should be a table which will not be wiped on roundstart. getroottable() is a good idea, defaults to getroottable();
// customNameSpace: The custom name to use for the CompLite Libraries' namespace. Should be passed as a string. Defaults to "CompLite"
// ChallengeScript: Pass a reference to the ChallengeScript table. Defaults to ::DirectorScript.MapScript.ChallengeScript
function InitializeCompLite(parentTable = getroottable() , customNameSpace = "CompLite", ChallengeScript = ::DirectorScript.MapScript.ChallengeScript )
{
	if(customNameSpace in parentTable)
	{
		local CompLite = parentTable[customNameSpace];
		CompLite.Globals.IncrementRoundNumber();
		CompLite.Globals.GSM.Reset();

		if(CompLite.Globals.GetCurrentRound() == 1)
		{
			CompLite.Globals.MapInfo.IdentifyMap(Entities);
		}

		ChallengeScript.DirectorOptions <- CompLite.ChallengeScript.DirectorOptions;
		ChallengeScript.Update <- CompLite.ChallengeScript.Update;
		return CompLite;
	}
	
	local CompLite = parentTable[customNameSpace] <- {};
	
	IncludeScript("gamestate_model", CompLite);
	IncludeScript("globaltimers", CompLite);
	IncludeScript("utils", CompLite);
	IncludeScript("modules", CompLite);
	
	CompLite.ChallengeScript <- {
		CompLite = CompLite
		DirectorOptions = {
			CompLite = CompLite
			function AllowWeaponSpawn( classname ) 
			{ 
				return CompLite.Globals.GSM.OnAllowWeaponSpawn(classname);
			}
			function ConvertWeaponSpawn( classname ) 
			{ 
				return CompLite.Globals.GSM.OnConvertWeaponSpawn(classname);
			}
			function GetDefaultItem( idx ) 
			{
				return CompLite.Globals.GSM.OnGetDefaultItem(idx);
			}
			function ConvertZombieClass( id ) 
			{ 
				return CompLite.Globals.GSM.OnConvertZombieClass(id);
			}
		}

		function Update()
		{
			CompLite.Globals.Timer.Update();
			CompLite.Globals.FrameTimer.Update();
			CompLite.Globals.GSM.DoFrameUpdate();
		}
	}

	CompLite.Globals <- CompLiteGlobals(CompLite, Director, CompLite.ChallengeScript.DirectorOptions);

	ChallengeScript.DirectorOptions <- CompLite.ChallengeScript.DirectorOptions;
	ChallengeScript.Update <- CompLite.ChallengeScript.Update;

	CompLite.Globals.MapInfo.IdentifyMap(Entities);

	return CompLite;
}

class CompLiteGlobals {
	constructor(NameSpace, director, dopts)
	{
		Timer = NameSpace.Timers.GlobalSecondsTimer();
		FrameTimer = NameSpace.Timers.GlobalFrameTimer();
		MapInfo = NameSpace.Utils.MapInfo();
		GSC = NameSpace.GameState.GameStateController();
		GSM = NameSpace.GameState.GameStateModel(GSC, director);
		MobResetti = NameSpace.Utils.ZeroMobReset(director, dopts, FrameTimer);
	}

	function IncrementRoundNumber() { m_iRoundNumber++; }
	function GetCurrentRound() { return m_iRoundNumber; }
	//public
	Timer = null;
	FrameTimer = null;
	MapInfo = null;
	GSM = null;
	GSC = null;
	MobResetti = null;
	
	// private
	m_iRoundNumber = 0;
}
gamestate_model
 
// vim: set ts=4
// L4D2 GameState Model for Mutation VScripts
// Copyright (C) 2012 ProdigySim
// All rights reserved.
// =============================================================================

// double include protection
if("GameState" in this) return;
GameState <- {
	ROUNDSTART_DELAY_INTERVAL = 2
};
IncludeScript("utils", this);

class GameState.GameStateModel
{
	constructor(controller, director)
	{
		m_controller = controller;
		m_pDirector = director;
	}

	function DoFrameUpdate()
	{
		if(m_bLastUpdateTankInPlay)
		{
			if(!m_pDirector.IsTankInPlay())
			{
				m_bLastUpdateTankInPlay = false;
				m_controller.TriggerTankLeavesPlay();
			}
		}
		else if(m_pDirector.IsTankInPlay())
		{
			m_bLastUpdateTankInPlay = true;
			m_controller.TriggerTankEntersPlay();
		}
		if(!m_bLastUpdateSafeAreaOpened && m_pDirector.HasAnySurvivorLeftSafeArea())
		{
			m_bLastUpdateSafeAreaOpened = true;
			m_controller.TriggerSafeAreaOpen();
		}
		if(!m_bRoundStarted && m_bHeardAWS && m_bHeardCWS && m_bHeardGDI 
			&& m_iRoundStartTime < Time()-m_roundstart_delay)
		{
			m_bRoundStarted = true;
			m_controller.TriggerRoundStart(GetCurrentRound());
		}
	}
	function OnAllowWeaponSpawn( classname )
	{
		m_bHeardAWS = true;
		m_iRoundStartTime = Time();
		return m_controller.TriggerAllowWeaponSpawn(classname);
	}
	function OnConvertWeaponSpawn( classname )
	{
		m_bHeardCWS = true;
		m_iRoundStartTime = Time();
		return m_controller.TriggerConvertWeaponSpawn(classname);
	}
	function OnGetDefaultItem( idx )
	{
		m_bHeardGDI = true;
		m_iRoundStartTime = Time();
		return m_controller.TriggerGetDefaultItem(idx);
	}
	function OnConvertZombieClass(id)
	{
		return m_controller.TriggerPCZSpawn(id);
	}

	function Reset()
	{
		m_bRoundStarted = false;
		m_bHeardAWS = false;
		m_bHeardCWS = false;
		m_bHeardGDI = false;
		m_iRoundStartTime = 0;
		m_bLastUpdateSafeAreaOpened = false;
	}

	// Check for various round-start even. ts before triggering OnRoundStart()
	m_bRoundStarted = false;
	m_bHeardAWS = false;
	m_bHeardCWS = false;
	m_bHeardGDI = false;
	m_iRoundStartTime = 0;

	m_bLastUpdateTankInPlay = false;
	m_bLastUpdateSafeAreaOpened = false;
	
	m_controller = null;
	m_pDirector = null;
	m_roundstart_delay = GameState.ROUNDSTART_DELAY_INTERVAL;
	static GetCurrentRound = Utils.GetCurrentRound;
};

class GameState.GameStateListener
{
	// Called on round start. These may be multiples of these triggered, unfortunately.
	function OnRoundStart(roundNumber) {}
	// Called when a player leaves saferoom or the saferoom timer counts down
	function OnSafeAreaOpened() {}
	// Called when tank spawns
	function OnTankEntersPlay() {}
	// Called when tank dies/leaves play
	function OnTankLeavesPlay() {}
	// Called when a player-controlled zombie is going to be spawned via ConvertZombieClass
	// This event will be chained--called on all Listeners with the modified id passed into successive calls.
	// id: SIClass id of the PCZ to be spawned
	// return another SIClass value to convert the PCZ spawn.
	function OnSpawnPCZ(id) {}
	// Called when a player-controlled zombie is going to be spawned via ConvertZombieClass
	// After conversions from OnSpawnPCZ have taken place
	// id: actual SIClass id to be spawned
	function OnSpawnedPCZ(id) {}
	// Called when DirectorOptions.GetDefaultItem() is called.
	// This event chain will notify all listeners, but only one return value will be used.
	// TODO: further abstraction to just have lists returned...
	// Should be at the beginning of the round normally.
	function OnGetDefaultItem(idx) {}
	// Called when DirectorOptions.AllowWeaponSpawn() is called. 
	// Should be at the beginning of the round normally, after conversions take place.
	// This event will stop being called on Listeners when one listener returns false.
	// classname: string classname of weapon to allow/disallow
	// return true to allow, false to disallow.
	function OnAllowWeaponSpawn(classname) {}
	// Called when DirectorOptions.ConvertWeaponSpawn is called
	// This event will be chained--called on all Listeners with the modified classname passed into successive calls.
	// classname: Classname of the weapon that would spawned
	// retun the classname that it should be converted to, or 0 for no conversion.
	function OnConvertWeaponSpawn(classname) {}
};

class GameState.GameStateController
{
	function AddListener(listener)
	{
		m_listeners.push(listener)
	}

	function TriggerRoundStart(roundNumber)
	{
		foreach(listener in m_listeners)
			listener.OnRoundStart(roundNumber);
	}
	function TriggerSafeAreaOpen()
	{
		foreach(listener in m_listeners)
			listener.OnSafeAreaOpened();
	}
	function TriggerTankEntersPlay()
	{
		foreach(listener in m_listeners)
			listener.OnTankEntersPlay();
	}
	function TriggerTankLeavesPlay()
	{
		foreach(listener in m_listeners)
			listener.OnTankLeavesPlay();
	}
	function TriggerPCZSpawn(id)
	{
		local retval = id;
		foreach(listener in m_listeners)
		{
			// Allow each listener to try to convert.
			// Not pretty in the long run but I'm okay with it.
			local ret = listener.OnSpawnPCZ(retval);
			if(ret != null) retval = ret;
		}

		// Simply notify everyone of the final value
		foreach(listener in m_listeners)
			listener.OnSpawnedPCZ(retval)
		return retval;
	}
	function TriggerAllowWeaponSpawn(classname)
	{
		foreach(listener in m_listeners)
		{
			// Cancel call chain once one listener returns false (says not to spawn it).
			if(listener.OnAllowWeaponSpawn(classname) == false) return false;
			// Interesting ! semantics
			//             null  false
			// !ret        true  true
			// ret==false  false true
			// ret==null   true  false
		}
		return true;
	}
	function TriggerConvertWeaponSpawn(classname)
	{
		local retcls = 0;
		foreach(listener in m_listeners)
		{
			local ret = listener.OnConvertWeaponSpawn(classname);
			if(ret != null && ret != 0) retcls = ret;
		}
		return retcls;
	}
	function TriggerGetDefaultItem(idx)
	{
		local retval = 0;
		foreach(listener in m_listeners)
		{
			local ret = listener.OnGetDefaultItem(idx);
			if(retval == 0 && ret != null) retval = ret;
		}
		return retval;
	}

	m_listeners = []
};
globaltimers
 
// vim: set ts=4
// Global Timers for L4D2 VScript Mutations
// Copyright (C) 2012 ProdigySim
// All rights reserved.
// =============================================================================


/* Usage:
	Create an instance of one of these timers, e.g.
	g_Timer = GlobalTimer()
	and/or
	g_FrameTimer = GlobalFrameTimer()
	
	Then run the timer's Update() function in your global "update" function.
	e.g. 
	function Update()
	{
		g_Timer.Update();
		g_FrameTimer.Update();
	}
	
	To add a timer, extend TimerCallback to create a callback.
	e.g.
	class MyCallback extends TimerCallback
	{
		function OnTimerElapsed()
		{
			Msg("My Timer has elapsed!!!\n");
		}
	}
	
	Then register it to the global timer of your choice,
	
 */

// double include protection
if("Timers" in this) return;

Timers <- {};

class Timers.TimerCallback
{
	/* OnTimerElapsed()
	Executed once the timer is elapsed in a GlobalTimer
	 */
	function OnTimerElapsed() {}
};

class Timers.GlobalTimer
{
	constructor()
	{
		m_callbacks = array(0);
		m_cbtimes = array(0);
	}
	// Returns the current time in some format that supports arithmetic operations
	// Overload this in your final class
	function GetCurrentTime() {