-- Top Gun 2
-- By JetBoom

OBJECTIVE_HEALTH = 500
VehicleTypes = {}
Vehicles = {}
PlayerHealths = {}
PlayerArmors = {}
DamageTypes = {} DamageTypes["bullet"] = 0.75 DamageTypes["antivehicle"] = 3.0 DamageTypes["weak"] = 0.5 DamageTypes["flak"] = 2.0
teams = {}
teams[TEAM_BLUE] = {name="Blue Butt Baboons", color={r=15,g=170,b=255}, Objective=0, Health=OBJECTIVE_HEALTH}
teams[TEAM_RED] = {name="Red Rear-end Rednecks", color={r=255,g=40,b=0}, Objective=0, Health=OBJECTIVE_HEALTH}
RestartRoundTemplate = 0
EndRound = false
_OpenScript("mouse.lua")

-- NoXious Database specific stuff. No need to delete. ----------
NoXious = true
MONEY_ROUNDWIN = 250
MONEY_KILL = 20
if NDB == nil then NDB = {} NoXious = false end
if NDB.AddMoney == nil then
	NDB.AddMoney = function(a, b, c) end
end
if NDB.GlobalSave == nil then
	NDB.GlobalSave = function() end
end
if TICKRATE == nil then TICKRATE = 1 end
-- End NoXious specific stuff. ----------------------------

function CreateResFileString()
	local str = [["resources"
{
"motdrh.txt" "file"
"materials/noxctf/rainbow.vmt" "file"
"materials/noxctf/rainbow.vtf" "file"
"materials/noxctf/yinyang.vmt" "file"
"materials/noxctf/yinyang.vtf" "file"
"materials/lm/lm.vmt" "file"
"materials/lm/lm.vtf" "file"
"materials/deathnotify/d_axe.vtf" "file"
"materials/deathnotify/d_axe.vmt" "file"
"materials/deathnotify/d_sword.vtf" "file"
"materials/deathnotify/d_sword.vmt" "file"
"materials/deathnotify/d_dragoonsword.vtf" "file"
"materials/deathnotify/d_dragoonsword.vmt" "file"
"models/peanut/conansword.mdl" "file"
"models/peanut/conansword.vvd" "file"
"models/peanut/conansword.phy" "file"
"models/peanut/conansword.dx80.vtx" "file"
"models/peanut/conansword.dx90.vtx" "file"
"models/peanut/conansword.sw.vtx" "file"
"models/mortarsynth_base.mdl" "file"
"models/mortarsynth_base.mdl.vvd" "file"
"models/mortarsynth_base.mdl.phy" "file"
"models/mortarsynth_base.mdl.dx80.vtx" "file"
"models/mortarsynth_base.mdl.dx90.vtx" "file"
"models/mortarsynth_base.mdl.sw.vtx" "file"
"materials/peanut/conansword.vmt" "file"
"materials/peanut/conansword.vtf" "file"
"sound/lm/lm.wav" "file"
"materials/mage/spellselect.vtf" "file"
"materials/mage/spellselect.vmt" "file"
"materials/mage/spellselect2.vtf" "file"
"materials/mage/spellselect2.vmt" "file"
"materials/darkmage/spellselect.vtf" "file"
"materials/darkmage/spellselect.vmt" "file"
"materials/divinemage/spellselect.vtf" "file"
"materials/divinemage/spellselect.vmt" "file"
"sound/nox/sunburstcluster_explode.wav" "file"
"sound/nox/sunburst_explode.wav" "file"
"sound/leeroyjenkins.wav" "file"
"sound/stfu.wav" "file"
"sound/banned.wav" "file"
"sound/nox/carjacked.wav" "file"
"sound/nox/DU.wav" "file"
"sound/nox/ET.wav" "file"
"sound/nox/IN.wav" "file"
"sound/nox/CHA.wav" "file"
"sound/nox/KA.wav" "file"
"sound/nox/RU.wav" "file"
"sound/nox/UN.wav" "file"
"sound/nox/ZO.wav" "file"
"sound/nox/invisoff.wav" "file"
"sound/nox/invison.wav" "file"
"sound/nox/shield.wav" "file"
"sound/nox/blink.wav" "file"
"sound/nox/heal.wav" "file"
"sound/nox/slowon.wav" "file"
"sound/nox/slowoff.wav" "file"
"sound/racing11.mp3" "file"
"sound/racing12.mp3" "file"
"sound/racing13.mp3" "file"
"sound/racing14.mp3" "file"
"sound/youlose2.wav" "file"
"sound/speach/obeyyourthirst3.wav" "file"
"sound/speach/obeyyourthirst2.wav" "file"
"sound/speach/obeyyourthirst.wav" "file"
"sound/nox/helirotor.wav" "file"
"sound/nox/player_death.wav" "file"
"sound/nox/lightning_impact.wav" "file"
"sound/nox/plasma_explode.wav" "file"
"sound/nox/vulcan_fire.wav" "file"
"sound/nox/plasmaturret_fire.wav" "file"
"sound/nox/berserkercharge.wav" "file"
"sound/nox/counterspell.wav" "file"
"sound/nox/inversion.wav" "file"
"sound/stomachram.wav" "file"
"sound/jbb/enemyscore.mp3" "file"
"sound/jbb/allyscore.mp3" "file"
"sound/jbb/knockout.mp3" "file"
"sound/jbb/respawning.mp3" "file"
"sound/jbb/ballsnatch.mp3" "file"
"sound/motdintro.mp3" "file"
"materials/nedm.vmt" "file"
"materials/nedm.vtf" "file"
"materials/necromancer/spellselect.vtf" "file"
"materials/necromancer/spellselect.vmt" "file"
"materials/deathnotify/d_magegeneric.vtf" "file"
"materials/deathnotify/d_magegeneric.vmt" "file"
"materials/deathnotify/d_darkmagegeneric.vtf" "file"
"materials/deathnotify/d_darkmagegeneric.vmt" "file"
"materials/deathnotify/d_divinemagegeneric.vtf" "file"
"materials/deathnotify/d_divinemagegeneric.vmt" "file"
"materials/deathnotify/d_necromancergeneric.vtf" "file"
"materials/deathnotify/d_necromancergeneric.vmt" "file"
}
]]
	return str
end

function CreateResFile()
	_file.Write("maps/".._GetCurrentMap()..".res", CreateResFileString())
end

function gamerulesStartMap()
	for i in teams do
		_TeamSetName(i, teams[i].name)
	end
	for x in teams do
		for i=1, 4000 do
			if _EntGetName(i) == string.lower(TeamString(x).."objective") then
				teams[x].Objective = i
				break
			end
		end
	end
	for i=1, 4000 do
		if _EntGetName(i) == "restartroundtemplate" then RestartRoundTemplate = i break end
	end
	if NoXious then
		CreateResFile()
	end
	_OpenScript("gamemodes/topgun2/mapprofiles/".._GetCurrentMap()..".lua")
end

function PickDefaultSpawnTeam(userid)
	_PlayerChangeTeam(userid, GetAutoTeam())
	return true
end

function GiveDefaultItems(userid)
	if _PlayerInfo(userid, "team") == TEAM_SPECTATOR then return end
	_PlayerGiveItem(userid, "weapon_physcannon")
	_PlayerGiveSWEP(userid, "weapons/topgun2/weapon_cannon.lua")
	--_PlayerGiveSWEP(userid, "weapons/topgun2/weapon_smg.lua")
end

function onShowTeam(userid)
	if InVehicle(userid) then return end
	if GetAutoTeam() ~= _PlayerInfo(userid, "team") then
		_PlayerKill(userid)
		_PlayerChangeTeam(userid, GetAutoTeam())
	end
end

function onShowHelp(userid)
	_GModRect_Start( "gmod/white" )
	 _GModRect_SetPos( 0.2, 0.3, 0.0, 0.0 )
	 _GModRect_SetColor( 0, 0, 0, 100 )
	 _GModRect_SetTime( 15, 0, 1 )
	_GModRect_Send( userid, 50 )

	_GModRect_Start( "gmod/white" )
	 _GModRect_SetPos( 0.198, 0.298, 0.604, 0.154 )
	 _GModRect_SetColor( 0, 0, 0, 150 )
	 _GModRect_SetTime( 15, 0, 1 )
	_GModRect_SendAnimate( userid, 50, 1, 0.2 )

	_GModRect_Start( "gmod/white" )
	 _GModRect_SetPos( 0.2, 0.3, 0.0, 0.0 )
	 _GModRect_SetColor( 0, 0, 0, 10 )
	 _GModRect_SetTime( 15, 0, 1 )
	_GModRect_Send( userid, 51 )

	_GModRect_Start( "gmod/white" )
	 _GModRect_SetPos( 0.2, 0.3, 0.6, 0.15 )
	 _GModRect_SetColor( 0, 0, 0, 50 )
	 _GModRect_SetTime( 15, 0, 1 )
	_GModRect_SendAnimate( userid, 51, 1, 0.2 )

	_GModText_Start( "Default" )
	 _GModText_SetPos( 0.21, 0.36 )
	 _GModText_SetColor( 255, 255, 255, 0 )
	 _GModText_SetTime( 15, 1, 1 )
	 _GModText_SetText( "Destroy the other team's objective to win the round.\nYou can use vehicle pads to spawn vehicles." )
	_GModText_Send( userid, 50 )
	
	_GModText_Start( "Default" )
	 _GModText_SetPos( 0.21, 0.36 )
	 _GModText_SetColor( 255, 255, 255, 255 )
	 _GModText_SetTime( 15, 1, 1 )
	_GModText_SendAnimate( userid, 50, 2, 0.2 )

	_GModText_Start( "ImpactMassive" )
	 _GModText_SetPos( 0.41, 0.295 )
	 _GModText_SetColor( 255, 255, 255, 0 )
	 _GModText_SetTime( 15, 1, 1 )
	 _GModText_SetText( "[HELP]" )
	_GModText_Send( userid, 51 )

	_GModText_Start( "ImpactMassive" )
	 _GModText_SetPos( 0.41, 0.295 )
	 _GModText_SetColor( 255, 255, 255, 255 )
	 _GModText_SetTime( 15, 1, 1 )
	_GModText_SendAnimate( userid, 51, 2, 0.2 )
end

function eventPlayerUseEntity(userid, entity)
	if string.lower(_EntGetName(entity)) == string.lower("vehiclepad"..TeamString(_PlayerInfo(userid,"team"))) or _EntGetName(entity) == "vehiclepad" then
		if not IsInRadius(userid, entity, 120) then return end
		local entities = _EntitiesFindInSphere(_EntGetPos(entity), 356)
		local e = 0
		for k,i in entities do
			if _EntGetName(i) == "vehiclespawnpoint" then
				e = i
			end
		end
		if e > 0 then
			VehiclePadMenu(userid, e)
		else
			VehiclePadMenu(userid, entity)
		end
	elseif Vehicles[entity] ~= nil then
		if not IsInRadius(userid, entity, 256) then return end
		ProcessVehicleEntry(userid, entity)
	elseif string.lower(_EntGetName(entity)) == string.lower(TeamString(_PlayerInfo(userid,"team")).."onlybutton") then
		if not IsInRadius(userid, entity, 150) then return end
		_EntFire(entity, "FireUser1", "", 0)
	end
end

function IsInRadius(a, b, dist)
	return Distance(_EntGetPos(a), _EntGetPos(b)) <= dist
end

function Distance(a, b)
	return math.abs(vecLength(vecSub(a,b)))
end

function VehicleSelect(userid, vehicletype)
	for i=109, 121 do
		_GModText_Hide(userid, i, 0.9)
	end
	if teams[_PlayerInfo(userid,"team")].VehicleStock[vehicletype] <= 0 then
		_PrintMessage(userid, 4, "No vehicles of that type available.")
		return
	end
	local tab = _EntitiesFindInSphere(_EntGetPos(userid), 456)
	local vehiclepad = userid
	for i in tab do
		if _EntGetName(tab[i]) == "vehiclespawnpoint" then vehiclepad = tab[i] end
		if Vehicles[tab[i]] ~= nil then
			_PlaySoundPlayer(userid, "buttons/button8.wav")
			_PrintMessage(userid, 4, "There is a vehicle in the way.")
			return
		end
	end
	CreateVehicle(userid, vecAdd(_EntGetPos(vehiclepad), VehicleTypes[vehicletype].CreationOffset), vehicletype)
end

function VehiclePadMenu(userid, vehiclepad)
	if not _PlayerInfo(userid, "alive") then return end
	local xpos = 0.04
	_GModText_Start("TargetID")
		_GModText_SetPos(xpos, 0.2)
		_GModText_SetColor(255, 50, 0, 255)
		_GModText_SetTime(99999, 0, 0)
		_GModText_SetText("Vehicles")
	_GModText_Send(userid, 109)

	local x = 0
	for i in VehicleTypes do
		x = x+1
		_GModText_Start("DefaultShadow")
		 _GModText_SetPos(xpos, 0.27+(x*0.03))
		 if teams[_PlayerInfo(userid,"team")].VehicleStock[i] > 0 then
			_GModText_SetColor(0, 255, 0, 255)
		 else
			_GModText_SetColor(255, 30, 0, 255)
		 end
		 _GModText_SetTime(99999, 0, 0)
		 _GModText_SetText("[ ] "..x..". ("..teams[_PlayerInfo(userid,"team")].VehicleStock[i].."/"..VehicleTypes[i].Stock..") "..VehicleTypes[i].Name..": "..VehicleTypes[i].Description)
		_GModText_Send(userid, 109+x)
	end

	_GModText_Start("TargetID")
	 _GModText_SetPos(xpos, 0.75)
	 _GModText_SetColor(255, 0, 0, 255)
	 _GModText_SetTime(99999, 0, 0)
	 _GModText_SetText("[ ] Exit Menu")
	_GModText_Send(userid, x+110)
	MouseOn(userid, xpos, 0.27)
	Mouse[userid].Data = "vehiclemenu:"..vehiclepad
end

function eventMouseClicked(userid, x, y)
	if string.find(Mouse[userid].Data, "vehiclemenu:") ~= nil then
		local vehiclepad = tonumber(string.sub(Mouse[userid].Data, 13))
		local x = 0
		for i in VehicleTypes do
			x = x+1
			if MouseNear(userid, 0.05, 0.045, 0.25+(x*0.029)) then
				MouseOff(userid)
				VehicleSelect(userid, i)
				return
			end
		end
		MouseOff(userid)
	end
	for i=109, table.getn(Classes)+111 do
		_GModText_Hide(userid, i, 0.9)
	end
end

function TeamString(intt)
	if intt == TEAM_RED then return "Red"
	elseif intt == TEAM_BLUE then return "Blue"
	elseif intt == TEAM_GREEN then return "Green"
	elseif intt == TEAM_YELLOW then return "Yellow"
	else return "Spectator" end
end

function GetAutoTeam()
	if _TeamNumPlayers(TEAM_RED) > _TeamNumPlayers(TEAM_BLUE) then
		return TEAM_BLUE
	else
		return TEAM_RED
	end
end

function eventPlayerKilled(killed, attacker, weapon)
	_PlayerAddDeath(killed, 1)
	if killed == attacker then
		_PlayerAddScore(killed, -1)
	elseif IsPlayer(attacker) then
		NDB.AddMoney(attacker, MONEY_KILL, false)
		_PlayerAddScore(attacker, 1)
	end
	if NoXious then
		_EntEmitSoundEx(killed, "nox/player_death.wav", 1.3, 1.0)
	end
end

oldTraceAttack = _TraceAttack
function newTraceAttack(ent, inflictor, attacker, damage, damagetype)
	if Vehicles[ent] then
		if damagetype then
			if DamageTypes[damagetype] then
				ProcessVehicleDamage(ent, attacker, math.ceil(damage*DamageTypes[damagetype]))
			else
				ProcessVehicleDamage(ent, attacker, math.ceil(damage))
			end
		else
			ProcessVehicleDamage(ent, attacker, math.ceil(damage))
		end
	elseif ent == teams[TEAM_BLUE].Objective then
		if _PlayerInfo(attacker, "team") ~= TEAM_BLUE then
			ProcessObjectiveHit(ent, attacker, damage, TEAM_BLUE)
		end
	elseif ent == teams[TEAM_RED].Objective then
		if _PlayerInfo(attacker, "team") ~= TEAM_RED then
			ProcessObjectiveHit(ent, attacker, damage, TEAM_RED)
		end
	else
		oldTraceAttack(ent, inflictor, attacker, damage)
	end
end
_TraceAttack = newTraceAttack

function ObjectiveRegenerate()
	if EndRound then return end
	for team in teams do
		teams[team].Health = teams[team].Health+20
		if teams[team].Health > OBJECTIVE_HEALTH then
			teams[team].Health = OBJECTIVE_HEALTH
		end
	end
	UpdateGlobalHUD(0)
end
AddTimer(5, 0, ObjectiveRegenerate)

function ProcessObjectiveHit(objective, attacker, damage, team)
	if EndRound then return end
	damage = math.abs(math.ceil(damage))
	teams[team].Health = teams[team].Health-damage
	UpdateGlobalHUD(0)
	if teams[team].Health <= 0 then
		ObjectiveDestroyed(team)
		_EntFire(objective, "break", "", 0)
	end
end

function UpdateGlobalHUD(userid)
	_GModRect_Start("gmod/white")
	 _GModRect_SetPos(0.35, 0.03, (teams[TEAM_RED].Health)*0.00075, 0.02)
	 _GModRect_SetTime(9999, 0, 0)
	 _GModRect_SetColor(255, 0, 0, 255)
	_GModRect_SendAnimate(userid, 5109, 0.5, 0.5)
	_GModRect_Start("gmod/white")
	 _GModRect_SetPos(0.35, 0.06, (teams[TEAM_BLUE].Health)*0.00075, 0.02)
	 _GModRect_SetTime(9999, 0, 0)
	 _GModRect_SetColor(25, 50, 255, 255)
	_GModRect_SendAnimate(userid, 5110, 0.5, 0.5)
end

function StartingHUD(userid)
	_GModText_Start( "Default" )
	 _GModText_SetPos( -1, 0.001 )
	 _GModText_SetColor( 255, 255, 255, 255 )
	 _GModText_SetTime( 9999, 0, 0 )
	 _GModText_SetText( "Objective Health" )
	_GModText_Send( userid, 9876 )
	_GModRect_Start("gmod/white")
	 _GModRect_SetPos(0.3, 0.0, 0.47, 0.1)
	 _GModRect_SetTime(99999, 0, 0)
	 _GModRect_SetColor(0, 0, 0, 240)
	_GModRect_Send(userid, 5108)
	_GModRect_Start("gmod/white")
	 _GModRect_SetPos(0.35, 0.03, (teams[TEAM_RED].Health)*0.00075, 0.02)
	 _GModRect_SetTime(9999, 0, 0)
	 _GModRect_SetColor(255, 255, 255, 255)
	_GModRect_Send(userid, 5109)
	_GModRect_Start("gmod/white")
	 _GModRect_SetPos(0.35, 0.06, (teams[TEAM_BLUE].Health)*0.00075, 0.02)
	 _GModRect_SetTime(9999, 0, 0)
	 _GModRect_SetColor(255, 255, 255, 255)
	_GModRect_Send(userid, 5110)
end

function eventPlayerActive(name, userid, steamid)
	StartingHUD(userid)
	UpdateGlobalHUD(userid)
	DrawObjectives(userid)
	_EntSetKeyValue(userid, "rendermode", "1")
end

function DrawObjectives(userid)
	_GModRect_Start( "deathnotify/swep_default")
	 _GModRect_SetPos(0, 0, 0.025, 0.025)
	 _GModRect_SetColor(255, 0, 0, 255)
	 _GModRect_SetTime(99999, 0, 0)
	 _GModRect_SetDelay(0)
	 _GModRect_SetEntityOffset(vector3(0, 0, 16))
	 _GModRect_SetEntity(teams[TEAM_RED].Objective)
	_GModRect_Send(userid, 884)
	_GModRect_Start( "deathnotify/swep_default")
	 _GModRect_SetPos(0, 0, 0.025, 0.025)
	 _GModRect_SetColor(0, 0, 255, 255)
	 _GModRect_SetTime(99999, 0, 0)
	 _GModRect_SetDelay(0)
	 _GModRect_SetEntityOffset(vector3(0, 0, 16))
	 _GModRect_SetEntity(teams[TEAM_BLUE].Objective)
	_GModRect_Send(userid, 885)
end

function ObjectiveDestroyed(team)
	EndRound = true
	_EntFire(RestartRoundTemplate, "FireUser1", "", 0)
	if NoXious then
		for i=1, _MaxPlayers() do
			if IsPlayerOnline(i) then
				if _PlayerInfo(i, "team") ~= team then
					NDB.AddMoney(i, MONEY_ROUNDWIN, false)
				end
			end
		end
	end
	NDB.GlobalSave()
	if team == TEAM_BLUE then
		AddTimer(10, 1, RestartRound, TEAM_RED)
		if NoXious then
			_PrintMessageAll(3, "All players from the "..teams[TEAM_RED].name.." team have won $"..MONEY_ROUNDWIN)
		end
		PrintMessageAll("The "..teams[TEAM_RED].name.." have won the round!", 255, 0, 0, 255)
	else
		AddTimer(10, 1, RestartRound, TEAM_BLUE)
		if NoXious then
			_PrintMessageAll(3, "All players from the "..teams[TEAM_BLUE].name.." team have won $"..MONEY_ROUNDWIN)
		end
		PrintMessageAll("The "..teams[TEAM_BLUE].name.." have won the round!", 25, 80, 255, 255)
	end
end

function RestartRound(winner)
	EndRound = false
	for k,i in teams do
		i.Health = OBJECTIVE_HEALTH
		_EntFire(i.Objective, "break", "", 0)
	end
	_EntFire(RestartRoundTemplate, "ForceSpawn", "", 0)
	for i in Vehicles do
		VehicleDestroyed(Vehicles[i].Owner, i)
	end
	AllPlayers(_PlayerRespawn)
	AddTimer(4, 1, ResetObjectiveEntID)
end

function ResetObjectiveEntID()
	for x in teams do
		for i=1, 4000 do
			if _EntGetName(i) == string.lower(TeamString(x).."objective") then
				teams[x].Objective = i
				break
			end
		end
	end
	UpdateGlobalHUD(0)
	DrawObjectives(0)
end

function eventPlayerSpawn(userid)
	_PlayerSetDrawViewModel(userid, true)
	_player.ShouldDropWeapon(userid, false)
	_EntFire(userid, "color", TeamColor(_PlayerInfo(userid,"team")), 0)
end

local files = _file.Find( "lua/gamemodes/topgun2/vehiclescripts/*.lua" )
for i in files do
    if files[i] ~= "." and files[i] ~= ".." then
		if _file.Exists( "lua/gamemodes/topgun2/vehiclescripts/"..files[i]) then
			_Msg("Opening vehicle script "..files[i].."\n")
			_OpenScript("gamemodes/topgun2/vehiclescripts/"..files[i])
		end
    end
end

function InVehicle(userid)
	for i in Vehicles do
		if Vehicles[i].Driver == userid then return true end
	end
	return false
end

for i in teams do
	teams[i].VehicleStock = {}
	for x in VehicleTypes do
		teams[i].VehicleStock[x] = VehicleTypes[x].Stock or 1
	end
end

function VehiclesThink()
	for i in Vehicles do
		if i <= 0 or Vehicles[i].Type == nil then
			Vehicles[i] = nil
		else
			doVehicleThink(i)
		end
	end
end
AddThinkFunction(VehiclesThink)

function doVehicleThink(vehicle)
	local vehicletype = Vehicles[vehicle].Type
	if VehicleTypes[vehicletype].onThink ~= nil then
		VehicleTypes[vehicletype].onThink(vehicle)
	end
	if not _PlayerInfo(Vehicles[vehicle].Driver, "alive") or not IsPlayerOnline(Vehicles[vehicle].Driver) then Vehicles[vehicle].Driver = 0 end
	if Vehicles[vehicle].Driver <= 0 then return end
	if _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_ATTACK2) then
		DriverExit(Vehicles[vehicle].Driver, vehicle)
		return
	end
	if _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_FORWARD) then
		if VehicleTypes[vehicletype].onForward ~= nil then
			VehicleTypes[vehicletype].onForward(vehicle)
		end
	elseif _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_BACK) then
		if VehicleTypes[vehicletype].onBackward ~= nil then
			VehicleTypes[vehicletype].onBackward(vehicle)
		end
	end
	if _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_MOVELEFT) then
		if VehicleTypes[vehicletype].onLeft ~= nil then
			VehicleTypes[vehicletype].onLeft(vehicle)
		end
	elseif _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_MOVERIGHT) then
		if VehicleTypes[vehicletype].onRight ~= nil then
			VehicleTypes[vehicletype].onRight(vehicle)
		end
	end
	if _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_ATTACK) then
		if VehicleTypes[vehicletype].onAttack ~= nil then
			VehicleTypes[vehicletype].onAttack(vehicle)
		end
	end
	if _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_JUMP) then
		if VehicleTypes[vehicletype].onJump ~= nil then
			VehicleTypes[vehicletype].onJump(vehicle)
		end
	elseif _PlayerIsKeyDown(Vehicles[vehicle].Driver, IN_DUCK) then
		if VehicleTypes[vehicletype].onDuck ~= nil then
			VehicleTypes[vehicletype].onDuck(vehicle)
		end
	end
end

function ProcessVehicleDamage(vehicle, attacker, damage)
	attacker = attacker or Vehicles[vehicle].Driver or Vehicles[vehicle].Owner
	if _PlayerInfo(attacker, "team") == Vehicles[vehicle].Team and Vehicles[vehicle].Owner ~= attacker then return end
	if Vehicles[vehicle] == nil then return end
	if Vehicles[vehicle].Type == nil then return end
	if VehicleTypes[Vehicles[vehicle].Type] == nil then return end
	damage = math.abs(damage*(VehicleTypes[Vehicles[vehicle].Type].DamageMultiply))
	Vehicles[vehicle].Health = Vehicles[vehicle].Health-damage
	if VehicleTypes[Vehicles[vehicle].Type].onDamaged ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].onDamaged(vehicle, attacker, damage)
	end
	_GModText_Start( "Default" )
	 _GModText_SetPos( 0.0, 0.0 )
	 _GModText_SetColor( 230, 0, 0, 255 )
	 _GModText_SetTime( 0.75, 0.2, 0.2 )
	 _GModText_SetAdditive(true)
	 _GModText_SetEntity(vehicle)
	 _GModText_SetEntityOffset(vector3(math.random(-25,25),math.random(-25,25),math.random(40,50)))
	 _GModText_SetText( "- "..math.floor(damage))
	_GModText_Send(attacker, attacker+vehicle+math.random(10000,22000))
	if VehicleTypes[Vehicles[vehicle].Type].HUD ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].HUD(vehicle)
	end
	if Vehicles[vehicle].Health <= 0 and Vehicles[vehicle].Health > -1000 then
		Vehicles[vehicle].Health = -5000
		VehicleDestroyed(attacker, vehicle)
	end
end

function CreateVehicle(owner, pos, vehicletype)
	if VehicleTypes[vehicletype] == nil then _Msg("Invalid vehicle type\n") return end
	if VehicleTypes[vehicletype].Model == nil and VehicleTypes[vehicletype].EntityType == "prop_physics" then return end
	for i in Vehicles do
		if Vehicles[i].Owner == owner then
			_PrintMessage(owner, 4, "You already have a vehicle spawned.")
			return
		end
	end
	local enttype = VehicleTypes[vehicletype].EntityType or "prop_physics"
	if not pos then
		PlayerLookTrace(owner, 300)
		pos = vecAdd(_TraceEndPos(), vector3(0,0,250))
	end
	if not vehicletype then	for i in VehicleTypes do vehicletype = VehicleTypes[i] break end end
	local ent = _EntCreate(enttype)
	if ent > 0 then
		if string.find(VehicleTypes[vehicletype].EntityType, "prop_") then
			_EntPrecacheModel(VehicleTypes[vehicletype].Model)
			_EntSetModel(ent, VehicleTypes[vehicletype].Model)
		end
		_EntSetPos(ent, pos)
		_EntSetKeyValue(ent, "rendermode", "1")
		if VehicleTypes[vehicletype].onPreCreated ~= nil then
			VehicleTypes[vehicletype].onPreCreated(ent)
		end
		_EntSpawn(ent)
		_EntSetName(ent, "scriptedvehicle:"..vehicletype)
		Vehicles[ent] = {}
		Vehicles[ent].Owner = owner
		Vehicles[ent].Team = _PlayerInfo(owner, "team")
		Vehicles[ent].Driver = 0
		Vehicles[ent].Type = vehicletype
		Vehicles[ent].Health = VehicleTypes[vehicletype].MaxHealth or 100
		Vehicles[ent].CarJacked = false
		for i=1, 64 do
			_EntFire(ent, "alpha", i*4, i*0.1)
		end
		_EntFire(ent, "alpha", "255", 6.4)
		_EntFire(ent, "color", TeamColor(_PlayerInfo(owner,"team")), 0)
		_EntEmitSoundEx(ent, "ambient/machines/thumper_startup1.wav", 1.0, 0.5)
		if VehicleTypes[vehicletype].onCreated ~= nil then
			VehicleTypes[vehicletype].onCreated(ent)
		end
		teams[Vehicles[ent].Team].VehicleStock[vehicletype] = teams[Vehicles[ent].Team].VehicleStock[vehicletype]-1
	end
end

function ProcessVehicleEntry(userid, vehicle)
	if not _PlayerInfo(userid, "alive") or not IsPlayerOnline(userid) then return end
	if not Vehicles[vehicle] then return end
	if InVehicle(userid) then return end
	if Vehicles[vehicle].Driver <= 0 then
		if Vehicles[vehicle].Team ~= _PlayerInfo(userid, "team") then
			CarJack(userid, vehicle)
		end
		DriverEnter(userid, vehicle)
	end
end

function CarJack(userid, vehicle)
	local vehicletype = Vehicles[vehicle].Type
	if not Vehicles[vehicle].CarJacked then
		teams[Vehicles[vehicle].Team].VehicleStock[vehicletype] = teams[Vehicles[vehicle].Team].VehicleStock[vehicletype]+1
	end
	_EntEmitSoundEx(vehicle, "nox/carjacked.wav", 1.25, 1.0)
	_EntFire(vehicle, "color", "255 255 255", 0)
	_EntFire(vehicle, "color", TeamColor(_PlayerInfo(userid, "team")), 1.0)
	Vehicles[vehicle].Team = _PlayerInfo(userid, "team")
	Vehicles[vehicle].Owner = userid
	Vehicles[vehicle].CarJacked = true
end

function DriverEnter(userid, vehicle)
	if Vehicles[vehicle].Driver > 0 then return end
	if VehicleTypes[Vehicles[vehicle].Type].onDriverEnter ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].onDriverEnter(vehicle)
	end
	Vehicles[vehicle].Driver = userid
	Vehicles[vehicle].Owner = userid
	PlayerHealths[userid] = _PlayerInfo(userid, "health")
	PlayerArmors[userid] = _PlayerInfo(userid, "armor")
	_PlayerSpectatorStart(userid, OBS_MODE_CHASE)
	_PlayerSetChaseCamDistance(userid, VehicleTypes[Vehicles[vehicle].Type].DriverCamDistance or 0)
	_PlayerSpectatorTarget(userid, vehicle)
	_PlayerRemoveAllWeapons(userid)
	if VehicleTypes[Vehicles[vehicle].Type].HUD ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].HUD(vehicle)
	end
	_EntEmitSound(vehicle, "ambient/levels/citadel/pod_close1.wav")
end

function DriverExit(userid, vehicle)
	if not _PlayerInfo(userid, "alive") or not IsPlayerOnline(userid) then return end
	if VehicleTypes[Vehicles[vehicle].Type].onDriverExit ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].onDriverExit(vehicle)
	end
	Vehicles[vehicle].Driver = 0
	_PlayerSpectatorEnd(userid)
	_PlayerRespawn(userid)
	_EntSetPos(userid, vecAdd(_EntGetPos(vehicle), VehicleTypes[Vehicles[vehicle].Type].ExitOffset))
	_PlayerSetHealth(userid, PlayerHealths[userid])
	if PlayerArmors[userid] > 0 then
		_PlayerSetArmor(userid, PlayerArmors[userid])
	end
	if VehicleTypes[Vehicles[vehicle].Type].HUD ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].HUD(vehicle)
	end
	if VehicleTypes[Vehicles[vehicle].Type].HideHUD ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].HideHUD(userid)
	end
	if Vehicles[vehicle].Health > 0 then
		_EntEmitSound(vehicle, "ambient/levels/citadel/pod_open1.wav")
		VehicleDestroyed(userid, vehicle)
	end
end

function VehicleDestroyed(attacker, vehicle)
	local vehicletype = Vehicles[vehicle].Type
	if VehicleTypes[Vehicles[vehicle].Type].onDestroyed ~= nil then
		VehicleTypes[Vehicles[vehicle].Type].onDestroyed(vehicle)
	end
	if not IsPlayerOnline(attacker) then
		for i=1, _MaxPlayers() do
			if IsPlayerOnline(i) then
				attacker = i
				break
			end
		end
	end
	if Vehicles[vehicle].Driver > 0 then
		local driver = Vehicles[vehicle].Driver
		_PlayerSpectatorEnd(driver)
		_PlayerRespawn(driver)
		_EntSetPos(driver, _EntGetPos(vehicle))
		if _PlayerInfo(attacker, "team") ~= _PlayerInfo(driver, "team") then
			AddTimer(0.25, 1, _TraceAttack, driver, attacker, attacker, 1000)
		else
			AddTimer(0.5, 1, _PlayerKill, driver)
		end
		if VehicleTypes[Vehicles[vehicle].Type].HideHUD ~= nil then
			VehicleTypes[Vehicles[vehicle].Type].HideHUD(driver)
		end
	end
	if not Vehicles[vehicle].CarJacked then
		teams[Vehicles[vehicle].Team].VehicleStock[vehicletype] = teams[Vehicles[vehicle].Team].VehicleStock[vehicletype]+1
	end
	Vehicles[vehicle] = nil
end

function TeamColor(num)
	if num ~= TEAM_SPECTATOR then
		return teams[num].color.r.." "..teams[num].color.g.." "..teams[num].color.b
	else
		return "255 255 255"
	end
end

Cannons = {}
function Cannon(userid, ignore, target)
	_EntEmitSound(userid, "weapons/stinger_fire1.wav")
	_EntEmitSound(userid, "weapons/rpg/rocketfire1.wav")
	local i = table.getn(Cannons)+1
	Cannons[i] = {}
	if ignore ~= nil then
		Cannons[i].pos = _EntGetPos(ignore)
		Cannons[i].ignore = ignore
	else
		Cannons[i].pos = _PlayerGetShootPos(userid)
		Cannons[i].ignore = userid
	end
	Cannons[i].ang = _PlayerGetShootAng(userid)
	Cannons[i].owner = userid
	Cannons[i].reps = 0
	Cannons[i].homingreps = 0
	if target ~= nil then
		Cannons[i].target = target
		if Vehicles[target] then
			if Vehicles[target].Driver > 0 then
				MissileWarning(Vehicles[target].Driver)
			end
		end
	else
		Cannons[i].target = 0
	end
end

function MissileWarning(userid)
	_GModText_Start( "Default" )
	 _GModText_SetPos( -1, 0.6 )
	 _GModText_SetColor( 255, 0, 0, 255 )
	 _GModText_SetTime( 0.9, 0.4, 0.4 )
	 _GModText_SetText( "Incoming Missile" )
	_GModText_Send( userid, 20000 )
	_GModText_Start( "Default" )
	 _GModText_SetPos( -1, 0.6 )
	 _GModText_SetColor( 255, 0, 0, 255 )
	 _GModText_SetTime( 0.9, 0.4, 0.4 )
	 _GModText_SetDelay( 0.8 )
	 _GModText_SetText( "Incoming Missile" )
	_GModText_Send( userid, 20001 )
	_GModText_SetDelay( 0 )
	_PlaySoundPlayer(userid, "ambient/alarms/klaxon1.wav")
	AddTimer(0.75, 3, _PlaySoundPlayer, userid, "ambient/alarms/klaxon1.wav")
end

function PrintMessage(userid, msg, r, g, b, a)
_GModText_Start( "Trebuchet24" )
 _GModText_SetPos( -1.0, 0.8 )
 _GModText_SetColor( r, g, b, a )
 _GModText_SetTime( 5, 1, 1 )
 _GModText_SetText( msg )
_GModText_Send( userid, 521 )
end

function PrintMessageAll(msg, r, g, b, a)
	PrintMessage(0, msg, r, g, b, a)
end

function CannonsTick()
	for i in Cannons do
		_TraceLine(Cannons[i].pos, Cannons[i].ang, 99999, Cannons[i].ignore)
		if not _TraceHit() or Cannons[i].reps > 300 then
			Cannons[i] = nil
		else
			_TraceLine(Cannons[i].pos, Cannons[i].ang, 135, Cannons[i].ignore)
			if _TraceHit() then
				Cannons[i].pos = _TraceEndPos()
				local ents = _EntitiesFindInSphere(Cannons[i].pos, 120)
				for x in ents do
					if _phys.HasPhysics(ents[x]) then
						_TraceAttack(ents[x], Cannons[i].owner, Cannons[i].owner, (130-math.abs(vecLength(vecSub(Cannons[i].pos,_EntGetPos(ents[x])))))*0.5)
					end
				end
				local ent2 = _EntCreate("env_explosion")
				if ent2 > 0 then
					_EntSetKeyValue(ent2, "spawnflags", "17")
					_EntSetPos(ent2, Cannons[i].pos)
					_EntSpawn(ent2)
					_EntFire(ent2, "explode", "", 0)
					_EntFire(ent2, "kill", "", 0.1)
				end
				Cannons[i] = nil
			else
				local ent = _EntCreate("env_sprite")
				if ent > 0 then
					_EntSetKeyValue(ent, "model", "sprites/muzzleflash"..math.random(1,3)..".spr")
					_EntSetKeyValue(ent, "rendermode", "5")
					_EntSetKeyValue(ent, "scale", "0.25")
					_EntSetKeyValue(ent, "spawnflags", "1")
					_EntSetPos(ent, Cannons[i].pos)
					_EntSpawn(ent)
					_EntFire(ent, "showsprite", "", 0)
					_EntFire(ent, "setscale", "0.2", 0.25)
					_EntFire(ent, "setscale", "0.15", 0.5)
					_EntFire(ent, "setscale", "0.1", 0.75)
					_EntFire(ent, "hidesprite", "", 0.9)
					_EntFire(ent, "kill", "", 1.0)
					_EntEmitSoundEx(ent, "weapons/explode"..math.random(3,5)..".wav", 0.9, 1.5)
				end
				local ents = _EntitiesFindInSphere(Cannons[i].pos, 45)
				for q,y in ents do
					if Vehicles[y] and y ~= Cannons[i].owner and y ~= Cannons[i].ignore then
						local ents = _EntitiesFindInSphere(Cannons[i].pos, 120)
						for x in ents do
							if _phys.HasPhysics(ents[x]) then
								_TraceAttack(ents[x], Cannons[i].owner, Cannons[i].owner, (130-math.abs(vecLength(vecSub(Cannons[i].pos,_EntGetPos(ents[x])))))*0.5)
							end
						end
						local ent2 = _EntCreate("env_explosion")
						if ent2 > 0 then
							_EntSetKeyValue(ent2, "spawnflags", "17")
							_EntSetPos(ent2, Cannons[i].pos)
							_EntSpawn(ent2)
							_EntFire(ent2, "explode", "", 0)
							_EntFire(ent2, "kill", "", 0.1)
						end
						Cannons[i] = nil
						break
					end
				end
				if Cannons[i] ~= nil then
					Cannons[i].pos = vecAdd(Cannons[i].pos, vecMul(Cannons[i].ang, vector3(135,135,135)))
					if Cannons[i].target > 0 then
						if Vehicles[Cannons[i].target] == nil or Cannons[i].homingreps >= 50 then Cannons[i].target = 0 end
						Cannons[i].homingreps = Cannons[i].homingreps + 1
						if math.abs(vecLength(vecSub(_EntGetPos(Cannons[i].target), Cannons[i].pos))) > 220 then
							Cannons[i].ang = vecAverage(Cannons[i].ang, vecAverage(Cannons[i].ang, vecAverage(Cannons[i].ang, vecNormalize(vecSub(_EntGetPos(Cannons[i].target), Cannons[i].pos)))))
						else
							Cannons[i].ang = vecAverage(Cannons[i].ang, vecAverage(Cannons[i].ang, vecNormalize(vecSub(_EntGetPos(Cannons[i].target), Cannons[i].pos))))
						end
						--Cannons[i].pos = vecAdd(Cannons[i].pos, vecMul(vecNormalize(vecSub(_EntGetPos(Cannons[i].target), Cannons[i].pos)), vector3(50, 50, 50)))
					end
				end
			end
		end
	end
end
AddTimer(0.075, 0, CannonsTick)

function onGravGunPickup(player, entity)
	if Vehicles[entity] then
		return Vehicles[entity].Team ~= _PlayerInfo(player,"team")
	end
	return true
end

function vecAverage(v1, v2)
	return vector3((v1.x+v2.x)/2, (v1.y+v2.y)/2, (v1.z+v2.z)/2)
end

function DoCannon(userid)
	local lock = 0
	local rep = 1
	while rep < 50 and lock <= 0 do
		PlayerLookTrace(userid, rep*64)
		local ents = _EntitiesFindInSphere(_TraceEndPos(), 110)
		for k,i in ents do
			if Vehicles[i] then
				if Vehicles[i].Team ~= _PlayerInfo(userid,"team") then
					if VehicleTypes[Vehicles[i].Type].Lockable then
						lock = i
					end
				end
			end
		end
		rep = rep+1
	end
	Cannon(userid, nil, lock)
	if lock > 0 then
		_PlaySoundPlayer(userid, "buttons/button3.wav")
	end
end

function NoDamageLuaExplosion(pos)
	local glow = _EntCreate("env_lightglow")
	if glow > 0 then
		_EntSetKeyValue(glow, "rendercolor" , "255 255 200")
		_EntSetKeyValue(glow, "VerticalGlowSize", "130")
		_EntSetKeyValue(glow, "HorizontalGlowSize", "130")
		_EntSetKeyValue(glow, "MinDist", 15)
		_EntSetKeyValue(glow, "MaxDist", 4096)
		_EntSetKeyValue(glow, "OuterMaxDist", 190)
		_EntSetKeyValue(glow, "GlowProxySize", "5")
		_EntSetPos(glow, vecAdd(pos, vector3(0,0,20)))
		_EntSpawn(glow)
		_EntFire(glow, "kill", "", 1.5)
		for y=1, 15 do
			_EntFire(glow, "color", 240-(y*15).." "..(240-(y*15)).." "..(150-(y*10)), y*0.09)
		end
	end
	local expl = _EntCreate("env_explosion")
	if expl > 0 then
		_EntSetPos(expl, pos)
		_EntSetKeyValue(expl, "spawnflags", "65")
		_EntSpawn(expl)
		_EntFire(expl, "explode", "", 0)
		_EntFire(expl, "kill", "", 0.05)
		_EntEmitSoundEx(expl, "ambient/explosions/explode_"..math.random(1,9)..".wav", 1.5, 1)
	end
	for i=1, math.random(2, 4) do
		local ent = _EntCreate("prop_physics")
		if ent > 0 then
			_EntSetPos(ent, pos)
			_EntSetModel(ent, "models/weapons/w_bugbait.mdl")
			_EntSetKeyValue(ent, "spawnflags", "516")
			_EntSpawn(ent)
			_phys.ApplyForceCenter(ent, vector3(math.random(-1500, 1500), math.random(-1500, 1500), math.random(1000, 4000)))
			local trail = _EntCreate("env_fire_trail")
			if trail > 0 then
				_EntSetPos(trail, _EntGetPos(ent))
				_EntSpawn(trail)
				_EntSetParent(trail, ent)
				_EntFire(trail, "kill", "", 4.5)
			end
			_EntFire(ent, "kill", "", 5)
		end
	end
	_util.ScreenShake(pos, 120, 120, 1.25, 250)
end

_EntPrecacheModel("models/weapons/w_bugbait.mdl")
function LuaExplosion(pos, damage, radius, owner)
	if damage < 0 then damage = 0 end
	if radius < 1 then radius = 1 end
	local ents = _EntitiesFindInSphere(pos, radius)
	for i in ents do
		_TraceAttack(ents[i], owner, owner, damage-Distance(pos, _EntGetPos(ents[i])))
	end
	local glow = _EntCreate("env_lightglow")
	if glow > 0 then
		_EntSetKeyValue(glow, "rendercolor" , "255 255 200")
		_EntSetKeyValue(glow, "VerticalGlowSize", "130")
		_EntSetKeyValue(glow, "HorizontalGlowSize", "130")
		_EntSetKeyValue(glow, "MinDist", radius*0.1)
		_EntSetKeyValue(glow, "MaxDist", radius*6)
		_EntSetKeyValue(glow, "OuterMaxDist", radius)
		_EntSetKeyValue(glow, "GlowProxySize", "5")
		_EntSetPos(glow, vecAdd(pos, vector3(0,0,20)))
		_EntSpawn(glow)
		_EntFire(glow, "kill", "", 1.5)
		for y=1, 15 do
			_EntFire(glow, "color", 240-(y*15).." "..(240-(y*15)).." "..(150-(y*10)), y*0.09)
		end
	end
	local expl = _EntCreate("env_explosion")
	if expl > 0 then
		_EntSetPos(expl, pos)
		_EntSetKeyValue(expl, "spawnflags", "65")
		_EntSpawn(expl)
		_EntFire(expl, "explode", "", 0)
		_EntFire(expl, "kill", "", 0.05)
		_EntEmitSoundEx(expl, "ambient/explosions/explode_"..math.random(1,9)..".wav", 1.5, 1)
	end
	if damage > 30 then
		for i=1, math.random(3, 5) do
			local ent = _EntCreate("prop_physics")
			if ent > 0 then
				_EntSetPos(ent, pos)
				_EntSetModel(ent, "models/weapons/w_bugbait.mdl")
				_EntSetKeyValue(ent, "spawnflags", "516")
				_EntSpawn(ent)
				_phys.ApplyForceCenter(ent, vector3(math.random(-1500, 1500), math.random(-1500, 1500), math.random(1000, 4000)))
				local trail = _EntCreate("env_fire_trail")
				if trail > 0 then
					_EntSetPos(trail, _EntGetPos(ent))
					_EntSpawn(trail)
					_EntSetParent(trail, ent)
					_EntFire(trail, "kill", "", 4.5)
				end
				_EntFire(ent, "kill", "", 5)
			end
		end
	end
	_util.ScreenShake(pos, damage*0.5, damage*2, 1.25, radius*1.25)
end

