All pastes #911654 Raw Edit

Anonymous

public text v1 · immutable
·published 2008-02-20 21:03 UTC
rendered paste body
--[[ ==================================================================================================================================== ]]
--   Protect the Prime Minister (server)
--   Requires mapmanager resource (included in server package)
--   Code is released as is and may be modified and/or redistributed provided correct credits are given
--   If you are running the 'Admin' resource (admin panel) you must remove the register command as PTPM uses its own
--[[ ==================================================================================================================================== ]]
local ptpm_mode_name = "Protect the Prime Minister version 1.1"

local TEAM_PSYCHO = 1
local TEAM_TERROR = 2
local TEAM_PRIMEMINISTER = 3
local TEAM_BODYGUARD = 4
local TEAM_COP = 5

local current_map

local crouchObject = {}
local crouchCorona = {}

local root = getRootElement()
local team_names = {
[1] = "Psychopath",
[2] = "Terrorist",
[3] = "Prime Minister",
[4] = "Bodyguard",
[5] = "Cop"
}
local pocket_money = 500
local current_pm = -1
local pm_health_penalty_safe = 0

local player_boundary_safe = {}
local player_blip = {}
local player_respawn_timer = {}
local player_knock = {}
local player_callvote_voted = {}
local player_admin = {}

local last_good_x = {}
local last_good_y = {}
local last_good_z = {}

local plan_active = 0
local plan_text = ""

local round_timer_counter = 0
local round_time
local game_teams = {}

local cant_drive_vehicle = {}
local cant_passenger_vehicle = {}
local respawn_table = {}

local supported = {1,1,0,0,0,1,0,0,1,1,0,0}

local vote_victim, vote_initiator, votes_left, vote_timer, vote_reason, vote_serial, vote_victim_name
local callvote_ban_tracker = {}
local callvote_ban_max = 0

local command_block = 0

local swapclass_victim = nil



function PtpmMapStart(map)
	outputServerLog("PTPM: map started")
	
	current_map = map
	
	vote_table = {0,0,0,0,0,0,0,0,0,0,0,0}
	
	local time_ = getRealTime()
	setTime(time_.hour,time_.minute)
	
	for index,player in ipairs(getElementsByType("player")) do
		if player then
			setCameraMode(player,"fixed")	
			SetupWardrobeForPlayerClientTrigger(player)
			fadeCamera(player,true)
			HideSpawnMenuTrigger(player)
--			PlayerSpawnSelectionSetupTrigger(player)
			ClientRoundStartedSetup(player)
			BoundarySafe(player,10)
			--distance_display_text = {}
			--distance_display_text_string = {}
		end
	end	
	
	local distance_display_element = getElementsByType("distance_display")
	distance_display = tonumber(getElementData(distance_display_element[1],"value"))
	local team_specific_radar_element = getElementsByType("team_specific_radar")
	team_specific_radar = tonumber(getElementData(team_specific_radar_element[1],"value"))	
	local misc_info_pm = getElementsByType("pm_health_bonus")
	pm_health_bonus = tonumber(getElementData(misc_info_pm[1],"value"))
	local misc_info_medic = getElementsByType("medic_health_bonus")		
	medic_health_bonus = tonumber(getElementData(misc_info_medic[1],"value"))
	local misc_info_can_drown = getElementsByType("pm_can_drown")		
	pm_can_drown = tonumber(getElementData(misc_info_can_drown[1],"value"))
	local misc_info_abandoned = getElementsByType("pm_abandoned_health_penalty")		
	pm_abandoned_health_penalty = tonumber(getElementData(misc_info_abandoned[1],"value"))
	local misc_info_health_increase_check = getElementsByType("pm_health_increase_check")		
	pm_health_increase_check = tonumber(getElementData(misc_info_health_increase_check[1],"value"))	
	pm_health_increase_current = 0.0
	pm_health_increase_previous = 100.0
	
	if distance_display==1 then
		setTimer(UpdateDistanceDisplay,300,0)
	end
	
	pm_fresh = 0
	current_pm = -1
	round_timer_counter = 0
	plan_active = 0
	plan_text = ""
	game_boundary_count = 0
	game_boundary_x = {}
	game_boundary_y = {}
	pm_health_penalty_safe = 0
	
	command_block = 0
	
	local currentmap = call(getResourceFromName"mapmanager","getRunningGamemodeMap")
	round_time = get(getResourceName(currentmap)..".round_time_data")
	
	for k,v in ipairs(getElementsByType("corner",root)) do -- load the boundary corners
		AddGameBoundaryCorner(getElementData(v,"x"),getElementData(v,"y"))
	end
	
	banned_cuboid = {}
	banned_cuboid_count = 0
	
	for k,v in ipairs(getElementsByType("cuboid",root)) do -- load the banned cuboids
		AddBannedCuboid(v)
	end	
	
    cant_drive_vehicle = {}
	cant_passenger_vehicle = {}
    for i=1,5 do -- max teams
      cant_drive_vehicle[i] = {}
	  cant_passenger_vehicle[i] = {}
      for j=1,700 do -- max (highest number ptpm uses) vehicles
        cant_drive_vehicle[i][j] = 0
		cant_passenger_vehicle[i][j] = 0
      end
    end
	
	for k,v in ipairs(getElementsByType("cant_drive_vehicle",root)) do -- load the vehicle permissions (driver)
		local team = tonumber(getElementData(v,"team")+1)
		cant_drive_vehicle[team][tonumber(getElementData(v,"model"))] = 1
	end
	
	for k,v in ipairs(getElementsByType("cant_passenger_vehicle",root)) do -- load the vehicle permissions (passenger)
		local team = tonumber(getElementData(v,"team")+1)
		cant_passenger_vehicle[team][tonumber(getElementData(v,"model"))] = 1
	end	
	
	respawn_table = {}
	
	for k,vehicle in ipairs(getElementsByType("vehicle")) do
		respawn_table[vehicle] = {}
		toggleVehicleRespawn(vehicle,true)
		setVehicleRespawnDelay(vehicle,10000)
		--setVehicleIdleRespawnDelay(vehicle,30000)
		setVehicleIdleRespawnDelayEx(vehicle,45000)
		setVehicleRespawnPosition(vehicle,getElementData(vehicle,"posX"),getElementData(vehicle,"posY"),getElementData(vehicle,"posZ"),
											getElementData(vehicle,"rotX"),getElementData(vehicle,"rotY"),getElementData(vehicle,"rotZ"))
		setElementData(source,"ptpm_vehicle_fresh",1)
		if getResourceName(map)=="ptpm_air_assault" then
			local colour = getVehicleColor(vehicle)
			if colour==79 then -- cop
				setElementData(vehicle,"ptpm_vehicle_team",5)
			elseif colour==85 then -- terror
				setElementData(vehicle,"ptpm_vehicle_team",2)
			elseif colour==86 then -- bguard
				setElementData(vehicle,"ptpm_vehicle_team",4)	
			end
		end
	end	
	
--[[	if getResourceName(map)=="ptpm_chiliad" then
		local object_root = getElementsByType("object",root) 
		
		for k,v in ipairs(object_root) do
			if k>1 and k<91 then	
			end
		end
	end]]
end
addEventHandler("onGamemodeMapStart",root,PtpmMapStart)


function AddBannedCuboid(root)
		banned_cuboid[banned_cuboid_count] = {}
		banned_cuboid[banned_cuboid_count].col = createColCuboid(getElementData(root,"posX"),getElementData(root,"posY"),getElementData(root,"posZ"),
												getElementData(root,"width"),getElementData(root,"depth"),getElementData(root,"height"))
		if banned_cuboid[banned_cuboid_count].col == false then outputServerLog("Banned Cuboid: Invalid arguments ("..banned_cuboid_count..")") return end
		banned_cuboid[banned_cuboid_count].telex = getElementData(root,"teleX")
		banned_cuboid[banned_cuboid_count].teley = getElementData(root,"teleY")
		banned_cuboid[banned_cuboid_count].telez = getElementData(root,"teleZ")
		banned_cuboid[banned_cuboid_count].telea = getElementData(root,"teleA")
		banned_cuboid[banned_cuboid_count].vehicles = getElementData(root,"vehicles")
		banned_cuboid[banned_cuboid_count].interior = getElementData(root,"interior")
		banned_cuboid[banned_cuboid_count].message = getElementData(root,"message")
		
		banned_cuboid_count = banned_cuboid_count+1
end


function AddGameBoundaryCorner(x,y)
	game_boundary_x[game_boundary_count] = x
	game_boundary_y[game_boundary_count] = y
	
--	outputServerLog("Boundary Corner: x: "..game_boundary_x[game_boundary_count].." y: "..game_boundary_y[game_boundary_count])
	game_boundary_count = game_boundary_count+1
end

function setVehicleIdleRespawnDelayEx(vehicle,delay)
        respawn_table[vehicle].delay = delay
end

function OnPlayerColShapeHit(element,colshape,dimension)
	local type_ = getElementType(element)
	for k = 1,#banned_cuboid do
		if banned_cuboid[k].col == colshape then			
			if type_=="player" then
				local vehicle = getPlayerOccupiedVehicle(element)
				if vehicle then
					if banned_cuboid[k].vehicles == 1 then
						setElementPosition(vehicle,banned_cuboid[k].telex,banned_cuboid[k].teley,banned_cuboid[k].telez)
						local x,y = getVehicleRotation(vehicle)
						setVehicleRotation(vehicle,x,y,banned_cuboid[k].telea)
						setElementInterior(vehicle,banned_cuboid[k].interior)
					else return 
					end
				elseif not vehicle then
					setElementPosition(element,banned_cuboid[k].telex,banned_cuboid[k].teley,banned_cuboid[k].telez)
					setPlayerRotation(element,banned_cuboid[k].telea)
					setElementInterior(element,banned_cuboid[k].interior)	
				end
				if banned_cuboid[k].message~=nil then
					outputChatBox(banned_cuboid[k].message,element)
				end		
			end
		end
	end
end
addEvent("OnPlayerColShapeHit",true)
addEventHandler("OnPlayerColShapeHit",root,OnPlayerColShapeHit)

function PtpmMapStop(map)	
	for k,vehicle in ipairs(getElementsByType("vehicle")) do
		if respawn_table[vehicle].timer then
			killTimer(respawn_table[vehicle].timer)
		end
		respawn_table[vehicle].timer = nil
	end
	
	distance_display = 0
--	distance_display_text = nil
--	distance_display_text_string = nil
	
	for k=1,5 do
		cant_drive_vehicle[k] = nil
		cant_passenger_vehicle[k] = nil
	end
	cant_drive_vehicle = nil
	cant_passenger_vehicle = nil
	
	game_boundary_x = nil
	game_boundary_y = nil
	game_boundary_count = 0
	
	pm_health_bonus = 0
	medic_health_bonus = 0
	pm_can_drown = 0
	pm_abandoned_health_penalty = 0
	pm_health_increase_check = 0
	
	triggerClientEvent(root,"UpdateMapVotesInMenu",root,{0,0,0,0,0,0,0,0,0,0,0,0})
	
	for index,player in ipairs(getElementsByType("player")) do
		if player then
			setPlayerTeam(player,nil)
			setPlayerNametagColor(player,255,255,255)
			setElementData(player,"ptpm_spawned",false)
			setElementData(player,"ptpm_class_type","null")
			setElementData(player,"ptpm_team",-1)
			setElementData(player,"ptpm_class",-1)
			setElementData(player,"deaths",0)
			setElementData(player,"kills",0)	
			last_good_x[player] = 0
			last_good_y[player] = 0
			last_good_z[player] = 0
			player_callvote_voted[player] = 0
			triggerClientEvent(player,"ResetMapvoteColours",root,-1,getElementData(player,"ptpm_mapvote"))
			triggerClientEvent(player,"ForceMapvoteMenuHide",root)
			setElementData(player,"ptpm_mapvote",-1)
--			BoundarySafe(player,5)
			if distance_display == 1 then
				textDisplayRemoveObserver(distance_display_text[player],player)
			end
			if crouchObject[player] then
				destroyElement(crouchObject[player])
				destroyElement(crouchCorona[player])
			end
			crouchObject[player] = nil
			crouchCorona[player] = nil
		end
	end
	outputServerLog("PTPM: map stopped")
end
addEventHandler("onGamemodeMapStop",root,PtpmMapStop)


function OutputModeMap(player)
	local currentmap = call(getResourceFromName"mapmanager","getRunningGamemodeMap")
	local currentmode = call(getResourceFromName"mapmanager","getRunningGamemode")
	outputChatBox("Mode: "..getResourceName(currentmode) .. " Map: "..getResourceName(currentmap),player)
end
addCommandHandler("mode",OutputModeMap)


function OnRoundEnd()
	local manager = getResourceFromName("mapmanager")
	vote_table = {0,0,0,0,0,0,0,0,0,0,0,0}
	
	for index, player in ipairs(getElementsByType("player")) do
		if player then
			local vote_ = getElementData(player,"ptpm_mapvote")
			if vote_~=-1 then
				vote_table[vote_] = vote_table[vote_] + 1
				local mapid = "ptpm_mapcount"..vote_
				setElementData(player,mapid,getElementData(player,mapid)+1)
			end
		end
	end
	
	local max_score=0
	for k = 1,12 do
		if vote_table[k]>max_score then max_score = vote_table[k] end
	end
	
	local map_ = -1
	repeat
		map_ = -1
		while map_==-1 do
			local proposal = math.random(12)
			if vote_table[proposal] == max_score then map_ = proposal end
		end
	until supported[map_]==1

	local maps = {
	"ptpm_ls_hydra",
	"ptpm_san_fierro",
	"ptpm_desert",
	"ptpm_area_51",
	"ptpm_lv_obj",
	"ptpm_air_assault",
	"ptpm_chiliad",
	"ptpm_countryside",
	"ptpm_los_santos",
	"ptpm_las_venturas",
	"ptpm_factory",
	"ptpm_bayside"
	}

	call(manager,"changeGamemodeMap",getResourceFromName(maps[map_]),getResourceFromName("ptpm"))
end	

--[[
function PtpmModeStart()
	outputServerLog("PTPM: mode started")
	local manager = getResourceFromName("mapmanager")
	call(manager,"changeGamemodeMap",getResourceFromName("ptpm_los_santos"),getResourceFromName("ptpm"))
	call(getResourceFromName("scoreboard"), "addScoreboardColumn", "Score")
	call(getResourceFromName("scoreboard"), "addScoreboardColumn", "kills")
	call(getResourceFromName("scoreboard"), "addScoreboardColumn", "deaths")
	
	setTimer(RoundTick,1000,0)
end]]
--addEventHandler("onGamemodeStart",getResourceRootElement(getThisResource()),PtpmModeStart)

function onThisResourceStart()
	outputServerLog("PTPM: mode started")
	local manager = getResourceFromName("mapmanager")
	call(manager,"changeGamemode",getResourceFromName("ptpm"))
	call(manager,"changeGamemodeMap",getResourceFromName("ptpm_los_santos"),getResourceFromName("ptpm"))
	call(getResourceFromName("scoreboard"), "addScoreboardColumn", "kills")
	call(getResourceFromName("scoreboard"), "addScoreboardColumn", "deaths")
	stopResource(getResourceFromName("votemanager"))
	stopResource(getResourceFromName("mapcycler"))
	stopResource(getResourceFromName("spawnmanager"))
	
	
	setTimer(RoundTick,1000,0)
	setTimer(BoundCheck,400,0)
	
	Commands()
	setMapName("Los Santos")
	setGameType("Ptpm")
	
	distance_display_text = {}
	distance_display_text_string = {}
	
	timer_display = textCreateDisplay()
	timer_display_text = textCreateTextItem("This is a timer message",0.5,0.25,"low",100,140,220,200,4,"center","top")
	textDisplayAddText(timer_display,timer_display_text)    

	swapclass_display = textCreateDisplay()
	swapclass_message = textCreateTextItem("- wants to swapclass with you",0.5,0.90,"low",255,70,0,200,2,"center","top")
	textDisplayAddText(swapclass_display,swapclass_message) 	

	game_teams = {}
	
	local teams_ = getElementsByType("team_data")
	for k,v in ipairs(teams_) do
		game_teams[k] = {}
		game_teams[k].team = createTeam(team_names[k])
		if k ~= 1 then
			setTeamFriendlyFire(game_teams[k].team,false)
		end
	end	
end
addEventHandler("onResourceStart",getResourceRootElement(getThisResource()),onThisResourceStart)


function onThisResourceStop()
	for k = 1,callvote_ban_max do
		if callvote_ban_tracker[k] then
			unbanSerial(callvote_ban_tracker[k].serial)
			outputServerLog("CALLVOTE: "..callvote_ban_tracker[k].name.." ("..callvote_ban_tracker[k].serial..") unbanned.")
			callvote_ban_tracker[k].serial = nil
			callvote_ban_tracker[k].timer = nil
			callvote_ban_tracker[k].name = nil
			callvote_ban_tracker[k] = nil
		end
	end
	
	for k = 1,#game_teams do
		destroyElement(game_teams[k].team)
		game_teams[k] = nil
	end
	game_teams = nil
end
addEventHandler("onResourceStop",getResourceRootElement(getThisResource()),onThisResourceStop)

function OnPlayerJoinFunc()
	local player_name = getClientName(source)
	setCameraMode(player,"fixed")
	setPlayerTeam(source,nil)
	setPlayerBlurLevel(source,20)
	setElementData(source,"ptpm_spawned",false)
	setElementData(source,"ptpm_team",-1)
	setElementData(source,"ptpm_class",-1)	
	setElementData(source,"ptpm_class_type","null")
	last_good_x[source] = 0
	last_good_y[source] = 0
	last_good_z[source] = 0
	setElementData(source,"ptpm_mapvote",-1)
	player_callvote_voted[source] = 0
	setElementData(source,"deaths",0)
	setElementData(source,"kills",0)
	
	setElementData(source,"ptpm_kills",0)
	setElementData(source,"ptpm_deaths",0)
	setElementData(source,"ptpm_pmvictory",0)							
	setElementData(source,"ptpm_pmkills",0)
	for i = 1,12 do
		local mapid = "ptpm_mapcount"..i
		setElementData(source,mapid,0)
	end
	for i = 1,5 do
		local spawned = "ptpm_spawned"..i
		setElementData(source,spawned,0)
	end
	fadeCamera(source,true)	
	player_boundary_safe[source] = 0
	player_blip[source] = nil
	player_respawn_timer[source] = nil
	player_knock[source] = true
	player_admin[source] = false
	
	distance_display_text[source] = textCreateDisplay()
	distance_display_text_string[source] = textCreateTextItem("Distance to -:\n-\n\nHis health is:\n-",0.08,0.45,"low",255,0,0,255,1,"center")
	textDisplayAddText(distance_display_text[source],distance_display_text_string[source])
	Motd(source)
	
	local name,found = string.gsub(getClientName(source),"#%x%x%x%x%x%x","")
	if found>0 then
		if string.len(name)>0 then
			outputChatBox("Nick cannot contain colour code(s).",source,255,0,0)
			triggerEvent("ChangePlayerNick",source,name)
		else
			kickPlayer(source,root,"Nick cannot be a colour code.")
		end
	end
end
addEventHandler("onPlayerJoin",root,OnPlayerJoinFunc)


function SetupWardrobeForPlayerClientTrigger(player)
	if (player) then
		triggerClientEvent(player,"SetupWardrobeForPlayerFunc",root)
	end
end


function HideSpawnMenuTrigger(player)
    if (player) then
		triggerClientEvent(player,"HideSpawnMenu",root)
	end
end

--[[
function PlayerSpawnSelectionSetupTrigger(player)
    if (player) then
		triggerClientEvent(player,"PlayerSelectSpawn",root)
	end
end]]

function ClientRoundStartedSetup(player)
	if player then
		triggerClientEvent(player,"ClientRoundStarted",root)
	end
end


function OnPlayerQuitFunc(reason)
	triggerClientEvent(source,"HideSpawnMenu",root)
	local player_name = getClientName(source)
	if source==current_pm then current_pm=-1 end
	local players = getElementsByType("player")
	local vote_table = {0,0,0,0,0,0,0,0,0,0,0,0}
	for index, player in ipairs(players) do
		if player then
			local vote_ = tonumber(getElementData(player,"ptpm_mapvote"))
			if vote~=nil and vote~=false and vote_>=0 then
				vote_table[vote_] = vote_table[vote_] + 1
			end
		end
	end
	setElementData(source,"ptpm_mapvote",-1)
	player_respawn_timer[source] = nil
	player_admin[source] = false
	distance_display_text[source] = nil
	distance_display_text_string[source] = nil
	triggerClientEvent(root,"UpdateMapVotesInMenu",root,vote_table)
	destroyBlipsAttachedTo(source)
	-- quitting whilst in a vehicle doesnt call onPlayerVehicleExit()
	local vehicle = getPlayerOccupiedVehicle(source)
	if vehicle~=false then
		local seat = getPlayerOccupiedVehicleSeat(source)
		OnPlayerVehicleExit(vehicle,seat,-1)
	end
	if crouchObject[source] then
		destroyElement(crouchObject[source])
		destroyElement(crouchCorona[source])
	end
	crouchObject[source] = nil
	crouchCorona[source] = nil
	
--[[	local account = getClientAccount(source)
	if not isGuestAccount(account) then
		setAccountData(account,"ptpm_kills",getElementData(source,"ptpm_kills"))
		setAccountData(account,"ptpm_deaths",getElementData(source,"ptpm_deaths"))
		setAccountData(account,"ptpm_pmkills",getElementData(source,"ptpm_pmkills"))
		setAccountData(account,"ptpm_pmvictory",getElementData(source,"ptpm_pmvictory"))
		
		setAccountData(account,"ptpm_spawned1",getElementData(source,"ptpm_spawned1"))
		setAccountData(account,"ptpm_spawned2",getElementData(source,"ptpm_spawned2"))
		setAccountData(account,"ptpm_spawned3",getElementData(source,"ptpm_spawned3"))
		setAccountData(account,"ptpm_spawned4",getElementData(source,"ptpm_spawned4"))
		setAccountData(account,"ptpm_spawned5",getElementData(source,"ptpm_spawned5"))
		
		setAccountData(account,"ptpm_mapcount1",getElementData(source,"ptpm_mapcount1"))
		setAccountData(account,"ptpm_mapcount2",getElementData(source,"ptpm_mapcount2"))
		setAccountData(account,"ptpm_mapcount3",getElementData(source,"ptpm_mapcount3"))
		setAccountData(account,"ptpm_mapcount4",getElementData(source,"ptpm_mapcount4"))
		setAccountData(account,"ptpm_mapcount5",getElementData(source,"ptpm_mapcount5"))
		setAccountData(account,"ptpm_mapcount6",getElementData(source,"ptpm_mapcount6"))
		setAccountData(account,"ptpm_mapcount7",getElementData(source,"ptpm_mapcount7"))
		setAccountData(account,"ptpm_mapcount8",getElementData(source,"ptpm_mapcount8"))
		setAccountData(account,"ptpm_mapcount9",getElementData(source,"ptpm_mapcount9"))
		setAccountData(account,"ptpm_mapcount10",getElementData(source,"ptpm_mapcount10"))
		setAccountData(account,"ptpm_mapcount11",getElementData(source,"ptpm_mapcount11"))
		setAccountData(account,"ptpm_mapcount12",getElementData(source,"ptpm_mapcount12"))
	end]]
end
addEventHandler("onPlayerQuit",root,OnPlayerQuitFunc)

function destroyBlipsAttachedTo(player)
	local attached = getAttachedElements(player)
	if attached~=false then
		for k,element in ipairs(attached) do
			if getElementType(element)=="blip" then
				destroyElement(element)
				player_blip[player] = nil
			end
		end
	end
end


function UpdateDistanceDisplay()
	local players = getElementsByType("player")
	local px,py,pz
	if current_pm~=-1 then
		px,py,pz = getElementPosition(current_pm)
	end
	for k,player in ipairs(players) do
		if player then
			if current_pm~=-1 and player~=current_pm then
				local x,y,z = getElementPosition(player)
				textItemSetText(distance_display_text_string[player],string.format("Distance to %s:\n%.1f\n\nHis health is:\n%.1f",getClientName(current_pm),getDistanceBetweenPoints3D(x,y,z,px,py,pz),getElementHealth(current_pm)))
						
--			"Distance to "..getClientName(current_pm)..":\n"..getDistanceBetweenPoints3D(x,y,z,px,py,pz).."\n\nHis health is:\n"..getElementHealth(current_pm))
			else
				textItemSetText(distance_display_text_string[player],"Distance to -:\n-\n\nHis health is:\n-")
			end
		end
	end
end


function ClientSpawnMenuTrigger(player)
    if (player) then
		triggerClientEvent(player,"PlayerSelectSpawn",root)
	end
end

function SpawnPlayerFunc(player,team,class,hide) -- hide denotes whether the player got here through the menu or through the script (ie: /reclass is through the menu, dying and respawning is through the script)
--	outputChatBox("Spawn with: Team: "..team.." Class: "..class,player)
	if player_respawn_timer[player] then killTimer(player_respawn_timer[player]) end
	player_respawn_timer[player] = nil
	
	if not isElement(player) then return end
	if CalcTeamBalance(player,team)==false then outputChatBox("That team is full!",player) return end
	local spawn_node1 = getElementByID(string.lower(team_names[team]))
	local spawn_info1 = getElementsByType("spawn",spawn_node1)
	if spawn_info1==false then outputChatBox("ERROR: spawn info false",player) return end
	
	local random_ = randInt(1,table.getn(spawn_info1))
	local px = getElementData(spawn_info1[random_],"posX") 
	local py = getElementData(spawn_info1[random_],"posY") 
	local pz = getElementData(spawn_info1[random_],"posZ")
	local rot = math.ceil(getElementData(spawn_info1[random_],"rot"))
	
	local spawn_node2 = getElementByID(string.lower(team_names[team]))
	local spawn_info2 = getElementsByType("skin",spawn_node2)
	if spawn_info2==false then outputChatBox("ERROR: skin spawn info false",player) return end
	if (isElement(spawn_info2[class])==false) then return end
	
	if hide==1 then
		HideSpawnMenuTrigger(source)
	end
	
	setElementInterior(player,0)
	
	-- reclassing whilst in a vehicle doesnt call onPlayerVehicleExit()
	local vehicle = getPlayerOccupiedVehicle(player)
	if vehicle~=false then
		local seat = getPlayerOccupiedVehicleSeat(player)
		OnPlayerVehicleExit(vehicle,seat,-1)
--		removePlayerFromVehicle(player)
	end
		
	local skin = getElementData(spawn_info2[class],"model")
	spawnPlayer(player,px,py,pz,rot,skin,0,0,game_teams[team].team)
--	local team_text = "ptpm_spawned"..team
--	setElementData(player,team_text,getElementData(player,team_text)+1)
	setCameraMode(player,"player")
	setCameraTarget(player,player)	
	
	local class_root = getElementByID(string.lower(team_names[team]))
	local class_root_child = getElementsByType("spawn",class_root)
	local class_element = getElementChild (class_root,class+#class_root_child-1)
	local class_type_string = getElementData(class_element,"type")
	local class_type
	if string.find(class_type_string,"medic")~=nil then
		class_type = "medic"
	else 
		class_type = "generic"
	end
	
	if getElementData(player,"ptpm_team")==TEAM_PRIMEMINISTER and getElementData(player,"ptpm_class")==1 then
		current_pm = -1
		outputChatBox(getClientName(player).." is no longer the Prime Minister.",root,255,255,64,true)
	end

	setTimer(setElementData,1000,1,player,"ptpm_spawned",true)
	setElementData(player,"ptpm_team",team)
	setElementData(player,"ptpm_class",class)
	setElementData(player,"ptpm_class_type",class_type)
	
	if ((class==1) and (team==TEAM_PRIMEMINISTER)) then 
		current_pm = player
		outputChatBox(getClientName(player).." is now the Prime Minister.",root,255,255,64,true)
		plan_active = 0
		pm_fresh = 1
		pm_health_penalty_safe = 6
	end
	
	if ((team==TEAM_BODYGUARD) or (team==TEAM_COP)) then
		if plan_active == 1 then
			Plan(player)
		end
	end

	if distance_display == 1 then
		if team~=TEAM_PSYCHO and team~=TEAM_PRIMEMINISTER then -- psychos arnt allowed to see it, pm doesnt need to see it
			textDisplayAddObserver(distance_display_text[player],player)
		else
			textDisplayRemoveObserver(distance_display_text[player],player)
		end
	end
	
	local red = getElementData(spawn_info2[class],"red")
	local green = getElementData(spawn_info2[class],"green")
	local blue = getElementData(spawn_info2[class],"blue")
	setPlayerNametagColor(player,red,green,blue)
	
	local wep1 = getElementData(spawn_info2[class],"wep1")
	local ammo1 = getElementData(spawn_info2[class],"ammo1")
	giveWeapon(player,wep1,ammo1)
	local wep2 = getElementData(spawn_info2[class],"wep2")
	local ammo2 = getElementData(spawn_info2[class],"ammo2")
	giveWeapon(player,wep2,ammo2)
	local wep3 = getElementData(spawn_info2[class],"wep3")
	local ammo3 = getElementData(spawn_info2[class],"ammo3")
	giveWeapon(player,wep3,ammo3)	
	
	setPlayerArmor(player,0)
	setElementHealth(player,100)
	setPlayerMoney(player,pocket_money)
	
--	setBlipColor(player_blip[player],red,green,blue,255)
	destroyBlipsAttachedTo(player)
	if team_specific_radar~=1 then
		player_blip[player] = createBlipAttachedTo(player,0,2,red,green,blue,150)
	else		
		player_blip[player] = createBlipAttachedTo(player,0,2,red,green,blue,150,0)
	end
	
	if ((class==1) and (team==TEAM_PRIMEMINISTER)) then 
		setBlipColor(player_blip[player],red,green,blue,255)
	end
	
	setPlayerStat(player,160,999) -- driving
	setPlayerStat(player,229,999) -- bike
	setPlayerStat(player,230,999) -- pedal bike
	setPlayerStat(player,225,999) -- underwater stamina
	setPlayerStat(player,165,999) -- energy
	setPlayerStat(player,22,999) -- stamina
	setPlayerStat(player,69,999) -- weapons
	setPlayerStat(player,70,999) 
	setPlayerStat(player,71,999)
	setPlayerStat(player,72,999)
	setPlayerStat(player,74,999)
	setPlayerStat(player,75,999)
	setPlayerStat(player,76,999)
	setPlayerStat(player,77,999)
	setPlayerStat(player,78,999)
	setPlayerStat(player,79,999)
	
	if crouchObject[player] then
		destroyElement(crouchObject[player])
		destroyElement(crouchCorona[player])
	end
	crouchObject[player] = nil
	crouchCorona[player] = nil
	
	BoundarySafe(player,10)
	
	triggerClientEvent(player,"PlayerRespawn",root)
end
addEvent("SpawnPlayer",true)
addEventHandler("SpawnPlayer",root,SpawnPlayerFunc)

function OnPlayerChatFunc(message,message_type)
	if message_type == 0 then -- normal chat
        cancelEvent()
		message = string.gsub(message, "#%x%x%x%x%x%x", "")
		local r,g,b = getPlayerNametagColor(source)
		local chattername = getClientName(source)
		chattername = string.gsub(chattername,"#%x%x%x%x%x%x","")
		if string.find(message,"!")==1 then -- team message (a '!' as character 1)
			message = string.sub(message,2)
			local team = getElementData(source,"ptpm_team")
			for index, player in ipairs(getElementsByType("player")) do
				if player then
					if SameTeam(getElementData(player,"ptpm_team"),team) then
						outputChatBox("(TEAM) "..chattername.."#FFFFFF: "..message,player,r,g,b,true)
					end
				end
			end
		else -- normal chat
			outputChatBox(chattername.."#FFFFFF: "..message,root,r,g,b,true)
		end
	elseif message_type == 1 then -- action
		cancelEvent()
		message = string.gsub(message, "#%x%x%x%x%x%x", "")
		local r,g,b = getPlayerNametagColor(source)
		local chattername = getClientName(source)
		chattername = string.gsub(chattername,"#%x%x%x%x%x%x","")
		outputChatBox(chattername.." "..message,root,r,g,b,true)
	elseif message_type == 2 then -- teamchat
		cancelEvent()
		outputChatBox("Use \"!message\" for team chat.",source)
	end
end
addEventHandler("onPlayerChat",root,OnPlayerChatFunc)


function ChangePlayerNick(nick)
	setClientName(source,nick)
end
addEvent("ChangePlayerNick",true)
addEventHandler("ChangePlayerNick",root,ChangePlayerNick)


function OnPlayerWastedFunc(ammo,killer,weapon,bodypart)
	setElementData(source,"deaths",getElementData(source,"deaths")+1)
	setElementData(source,"ptpm_deaths",getElementData(source,"ptpm_deaths")+1)
	
	if killer then
		if (getElementType(killer)=="player") then
			setElementData(killer,"kills",getElementData(killer,"kills")+1)
			setElementData(killer,"ptpm_kills",getElementData(source,"ptpm_kills")+1)
		--	setElementData(killer,"ptpm_weapon_"..getWeaponNameFromID(weapon),getElementData(killer,"ptpm_weapon_"..getWeaponNameFromID(weapon))+1)
		end
	end
	
	if source == current_pm then
		EveryoneViewsBodyClientTrigger(current_pm)
		if (killer) then
			if (getElementType(killer)=="player") then
				local killer_team = getElementData(killer,"ptpm_team")
				if killer_team == TEAM_TERROR then
					outputChatBox("The Prime Minister was murdered by the Terrorists!",root)
					setElementData(killer,"ptpm_pmkills",getElementData(killer,"ptpm_pmkills")+1)
				elseif killer_team == TEAM_COP then
					outputChatBox("The Prime Minister was killed by the Cops!",root)
				elseif killer_team == TEAM_BODYGUARD then
					outputChatBox("The Prime Minister was killed by his treacherous bodyguards!",root)
				elseif killer_team == TEAM_PSYCHO then
					outputChatBox("The Prime Minister was killed by a Psycho!",root)
					setElementData(killer,"ptpm_pmkills",getElementData(killer,"ptpm_pmkills")+1)
				else 
					outputChatBox("The Prime Minister was killed in an accident!",root)
				end
			else
				outputChatBox("The Prime Minister was killed in an accident!",root)
			end
		else
			outputChatBox("The Prime Minister was killed in an accident!",root)
		end
	else
		player_respawn_timer[source] = setTimer(SpawnPlayerFunc,5000,1,source,getElementData(source,"ptpm_team"),getElementData(source,"ptpm_class"),0)
	end
end
addEventHandler("onPlayerWasted",root,OnPlayerWastedFunc)

function CalcTeamBalance(player,team)
	if ((team==TEAM_PRIMEMINISTER) and (countPlayersInTeam(game_teams[TEAM_PRIMEMINISTER].team)>0)) then return false end -- already 1 pm
	if ((team==TEAM_PRIMEMINISTER) and (countPlayersInTeam(game_teams[TEAM_PRIMEMINISTER].team)==0)) then return true end -- be the pm	
	if getPlayerTeam(player) == team then return true end -- same team (not pm though)
	if getPlayerCount()<=100 then return true end -- less than 6 players
	if team==TEAM_PSYCHO then return true end -- psycho always works	

	local t_count = countPlayersInTeam(game_teams[TEAM_TERROR].team)
	local b_count = countPlayersInTeam(game_teams[TEAM_BODYGUARD].team)
	local c_count = countPlayersInTeam(game_teams[TEAM_COP].team)
	
	local team_count = t_count + b_count + c_count
	
--	if ((team+1~=3) and (team+1~=1)) then team_count = team_count + 1 end
	team_count = team_count + 1

	if ((getPlayerTeam(player)~=TEAM_PRIMEMINISTER) and (getPlayerTeam(player)~=TEAM_PSYCHO)) then team_count = team_count - 1 end

	local prebalancedness = 0.0 -- current balance
	local postbalancedness = 0.0 -- requested balance
	
	if ((b_count*100)/team_count > 30) then return false end -- too many bguards
	
	prebalancedness = prebalancedness + 0.42 * b_count 	-- a bodyguard is worth 2 cops
	prebalancedness = prebalancedness + 0.28 * c_count
	prebalancedness = prebalancedness + -0.28 * t_count
	
	if team==TEAM_TERROR then t_count = t_count+1
	elseif team==TEAM_BODYGUARD then b_count = b_count+1
	elseif team==TEAM_COP then c_count = c_count+1 end
	
	postbalancedness = postbalancedness + 0.42 * b_count
	postbalancedness = postbalancedness + 0.28 * c_count
	postbalancedness = postbalancedness + -0.28 * t_count
	
	if team_count==0 then prebalancedness = 0 end -- no team players when request was made, so allow spawn

	local prepain = (math.abs(prebalancedness)*100) / team_count  -- absolute value
	local postpain = (math.abs(postbalancedness)*100) / team_count
	
	prepain = math.ceil(prepain)
	postpain = math.ceil(postpain)

	if (((prepain<=10) or (postpain < prepain)) and (team~=TEAM_BODYGUARD)) then return true end  -- everything ok
	
	-- not ok
	return false
end

function RoundTick()
	round_timer_counter = round_timer_counter + 1
	
	if pm_health_bonus == 1 then
		if current_pm~=-1 then
			if round_timer_counter%5==0 then
				local health = getElementHealth(current_pm)
				if ((health+1)<=100) then
					setElementHealth(current_pm,health+1)
				else 
					setElementHealth(current_pm,100)
				end
			end
		end
	end
	
	if medic_health_bonus == 1 then
		for index, player in ipairs(getElementsByType("player")) do
			if player then
				if getElementData(player,"ptpm_class_type")=="medic" then
					local health = getElementHealth(player)
					if ((health+1)<=100) then
						setElementHealth(player,health+1)
					else 
						setElementHealth(player,100)
					end
				end
			end
		end
	end
	
	if round_timer_counter==round_time then
		EveryoneViewsBodyClientTrigger(current_pm)
		outputChatBox("The Prime Minister Survived!",root)
		if current_pm~=-1 then
			setElementData(current_pm,"ptpm_pmvictory",getElementData(current_pm,"ptpm_pmvictory")+1)
		end
	end	
	
	if (round_timer_counter%150==0 and round_timer_counter>0 and round_timer_counter<round_time) then
		local minutes = math.floor((round_time - round_timer_counter) / 60)
		local seconds = math.floor((round_time - round_timer_counter) % 60)
		textItemSetText(timer_display_text,minutes..":"..seconds.." minutes remaining")	
		for index, player in ipairs(getElementsByType("player")) do
			if player then
				textDisplayAddObserver(timer_display,player)
			end
		end
	elseif (round_timer_counter%150==8 and round_timer_counter>0 and round_timer_counter<round_time) then
		for index, player in ipairs(getElementsByType("player")) do
			if player then
				textDisplayRemoveObserver(timer_display,player)
			end
		end
	end	

	if current_pm~=-1 then	
		if pm_can_drown==1 and isPlayerInWater(current_pm)==true then
			killPlayer(current_pm)
			pm_health_increase_current = 0.0
			pm_health_increase_previous = 100.0
		end
	end
	
	if current_pm~=-1 then
		if pm_abandoned_health_penalty~=0 and not getPlayerOccupiedVehicle(current_pm) and pm_fresh==0 then
			if pm_health_penalty_safe>0 then pm_health_penalty_safe=pm_health_penalty_safe-1 end
			if pm_health_penalty_safe==0 then
				if round_timer_counter%pm_abandoned_health_penalty==0 then
					ChangeHealth(current_pm,-2)
				end
			end
		end
	end
	
	if current_pm~=-1 then
		if pm_health_increase_check==1 then
			if getElementHealth(current_pm)>0 then
				pm_health_increase_current = getElementHealth(current_pm)
				if pm_health_increase_current > pm_health_increase_previous and not getPlayerOccupiedVehicle(current_pm) then
					setElementHealth(current_pm,pm_health_increase_previous)
				end
				pm_health_increase_previous = pm_health_increase_current
			end
		end
	end
end

function BoundCheck()
	for index, player in ipairs(getElementsByType("player")) do
		if player then
			if getElementData(player,"ptpm_spawned")==true then
				local x,y,z = getElementPosition(player)
				if z<1000 then
					if player_boundary_safe[player]>0 then player_boundary_safe[player] = player_boundary_safe[player]-1 end
					if player_boundary_safe[player]==0 then 
						if PlayerOutOfBounds(x,y)==true then							
							outputChatBox("You are out of bounds!",player)
							local good_x = last_good_x[player]
							local good_y = last_good_y[player]
							local good_z = last_good_z[player]
							local vehicle = getPlayerOccupiedVehicle(player)
							if vehicle~=false and player==getVehicleController(vehicle) then	
								setElementPosition(vehicle,good_x,good_y,good_z)
								local rx,ry,rz = getVehicleRotation(vehicle)
								setVehicleRotation(vehicle,rx,ry,(rz+180)%361)
								x,y,z = getElementVelocity(vehicle)
								setElementVelocity(vehicle,x-(x*2),y-(y*2),z-(z*2))
								BoundarySafe(player,2)
							else
								setElementPosition(player,good_x,good_y,good_z)
								x,y,z = getElementVelocity(player)
								setElementVelocity(player,0,0,0)
								BoundarySafe(player,2)
							end	
						else
							last_good_x[player] = x
							last_good_y[player] = y
							last_good_z[player] = z
						end		
					end
				end
			end
		end
	end
end

function BoundarySafe(player,amount)
	player_boundary_safe[player] = amount
end

function ChangeHealth(player,amount)
	local health = getElementHealth(player)
	if ((health+amount)<=100 and (health+amount)>0) then
		setElementHealth(player,health+amount)
	elseif (health+amount<=0) then
		killPlayer(player)
	else
		setElementHealth(player,100)
	end
end

function Motd(player)
	outputChatBox("Welcome to "..ptpm_mode_name..".",player)
	outputChatBox("Select a character class, and have fun!",player)
	outputChatBox("Updates: Version 1.1 released!",player)
	outputChatBox("Please report all bugs to the forum (press f9 for url)",player)
 	outputChatBox("Use /motd to see this \"message of the day\".",player)
end

function PlayerSwapclass(player,command,victim)
	if command_block==1 then return end
	if swapclass_victim~=nil then outputChatBox("You have already sent a swapclass offer to someone else.",player) return end
	local your_team = getElementData(player,"ptpm_team")
	if your_team ~= TEAM_PRIMEMINISTER then outputChatBox("Only the Prime Minister may use this command. (team: "..your_team..")",player) return end
	local your_class = getElementData(player,"ptpm_class")
	if your_class ~= 1 then outputChatBox("Only the Prime Minister may use this command. (class: "..your_class")",player) return end
	
	local victim_element = GetElementFromName(player,victim)
	if victim_element == false then return end
	if player == victim_element then outputChatBox("You may not swapclass with yourself.",player) return end
	local victim_team = getElementData(victim_element,"ptpm_team")
	if victim_team == -1 then outputChatBox("Invalid arguments. Usage: /swapclass <player_name>",player) return end
	local victim_class = getElementData(victim_element,"ptpm_class")
	if victim_class == -1 then outputChatBox("Invalid arguments. Usage: /swapclass <player_name>",player) return end
	
	-- both players are spawned with a valid team/class, so proceed to show message
	textItemSetText(swapclass_message,getClientName(player).." wants to swapclass with you. Type /y to accept & /n to decline")	
	textDisplayAddObserver(swapclass_display,victim_element)
	
	outputChatBox("Swapclass offer sent to "..getClientName(victim_element),player)
	
	swapclass_victim = victim_element
end

function PrintTime(player)
	if command_block==1 then return end
	local minutes = math.floor((round_time - round_timer_counter) / 60)
	local seconds = math.floor((round_time - round_timer_counter) % 60)
	outputChatBox("Time left: "..minutes..":"..seconds,player)
end

function EveryoneViewsBodyClientTrigger(current_pm)
	for index, player in ipairs(getElementsByType("player")) do
		if player then
			if player_blip[player] then
				setBlipColor(player_blip[player],0,0,0,0)
			end
			removePlayerFromVehicle(player)
		end
	end
	if current_pm~=-1 then
		local x,y,z = getElementPosition(current_pm)
		triggerClientEvent(root,"EveryoneViewsBody",root,current_pm,x,y,z)
	else		
		triggerClientEvent(root,"EveryoneViewsBody",root,current_pm,-1,-1,-1)
	end
	triggerClientEvent(root,"ForceMapvoteMenuShow",root)
	setTimer(OnRoundEnd,7000,1)
	command_block = 1
end

function PrintPmName(player)
	if command_block==1 then return end
	if current_pm ~= -1 then
		local pm = getClientName(current_pm)
		if pm~=false then
			outputChatBox("Current Prime Minister: "..pm,player)
		end
	else 
		outputChatBox("There is currently no Prime Minister.",player)
	end
end

function KillPlayer(player)
	if command_block==1 then return end
	if player == current_pm then outputChatBox("The Prime Minister may not kill himself.",player) return end
	
	killPlayer(player)
end

function ExplainRole(player)
	if command_block==1 then return end
	local team = getElementData(player,"ptpm_team")
	if team==TEAM_PSYCHO then 
		outputChatBox("Nobody wants to be your friend.  So trust noone.  Kill them all.",player);
	elseif team==TEAM_TERROR then 
		outputChatBox("Your role is to try and kill the Prime Minister(yellow) before the timer runs out. You must work with the",player)
		outputChatBox("other terrorists(pink) as a team. You must avoid the cops(blue) as they will hunt you.",player)
		outputChatBox("Beware of psychopaths(orange), they will kill anyone.",player)
		--if (obj_counter>0) then
		--		outputChatBox("The Prime Minister and his bodyguards will be visiting areas of the city.  These",player);
		--		outputChatBox("are red on the radar.  You should try and ambush him on his way there, siege him",player);
		--		outputChatBox("when he is there, and drive him away.  If the Prime Minister achieves his objectives",player);
		--		outputChatBox("then you lose the game.",player);
		--end
	elseif team==TEAM_PRIMEMINISTER then 
		--if (obj_counter==0) then
		outputChatBox("Your role is to avoid being killed by terrorists(pink) or psychopaths(orange) until the timer runs out.",player)
		outputChatBox("Use /timeleft to find out how long there is left.",player);
	    --else
		--outputChatBox("Your role is to visit and each of the objectives in order.  You must defend the objective",player);
		--outputChatBox("for the specified time before the next objective will be revealed.  Terrorists(pink) and",player);
		--outputChatBox("psychopaths(orange) will try to kill you.  If you die, the terrorists win.",player);
		--outputChatBox("THERE IS NO TIME LIMIT FOR THIS GAME!",player);
	    --end
		---	outputChatBox("You must work with your loyal bodyguards(green), they will protect you.",player);
		--	outputChatBox("You are to co-operate with the local police(blue), who will hunt the terrorists.",player);
	elseif team==TEAM_BODYGUARD then
		outputChatBox("Your duty is to stay with the Prime Minister(yellow) and protect him from harm. Terrorists(pink) will soon",player)
		outputChatBox("try and murder him.  Also beware of Psychopaths(orange). You are to co-operate with the local police(blue),",player)
		outputChatBox("who will hunt the terrorists.",player);
		--if (obj_counter>0) then
		--		outputChatBox("The Prime Minister will be visiting areas of the city.  These are red on the radar.",player);
		--		outputChatBox("The terrorists know where he needs to go, so you must prevent them from ambushing or",player);
		---		outputChatBox("successfully sieging the Prime Minister.  If he is killed, you lose the game.",player);
		--end
	elseif team==TEAM_COP then
		outputChatBox("Your orders are to kill the terrorists(pink) without harming the bodyguards(green) or the Prime Minister(yellow).",player)
		outputChatBox("Also beware of psychopaths(orange).  Protect the Prime Minister!",player);
		--if (obj_counter>0) then
		--		outputChatBox("The Prime Minister and his bodyguards will be visiting areas of the city.  These",player);
		--		outputChatBox("are red on the radar.  You should focus your efforts there, clean out the terrorists",player);
		--		outputChatBox("so that the prime minister can go in.  Then defend the area until he is done.",player);
		--end
	end

	local type = getElementData(player,"ptpm_class_type")
	if type=="medic" then
		outputChatBox("You are a medic, you can heal people with /heal.",player)
	end
	--if (safehouse_exists) then
	--	outputChatBox("Only terrorists and bodyguards may fly the hydra or seasparrow.",player);
	--	outputChatBox("The Prime Minister's safehouse (red) is a hydra/seasparrow free zone.",player);
	--end
end

function PrintHelp(player)
	outputChatBox("Press F9 or type /gamehelp to see the helpbox.",player)
	outputChatBox("/reclass (change class) /swapclass <person> (for pm) /intel",player)
	outputChatBox("/help  /duty  /motd  /pm  /timeleft  /kill  /heal <player>",player)
	outputChatBox("/plan <text> /plan (show plan) /knock <player> /map",player)
	outputChatBox("/mapvote /register /players /callvote <player> /endvote",player)
end

function GetCameraMode(player)
	local cam = getCameraMode(player)
	if cam~=false then
		outputChatBox("cam: "..cam,player)
	end
end

function PlayerHealPlayer(medic,command,intended_patient_name)	
	if command_block==1 then return end
	if getElementData(medic,"ptpm_class_type")~="medic" then -- must be a medic
		outputChatBox("You are not a medic!",medic) return
	end
	
	local intended_patient = GetElementFromName(medic,intended_patient_name)
	if intended_patient == false then return end
		
	if medic==intended_patient then -- cant heal yourself
		outputChatBox("Physicians may not heal themselves!",medic) return
	end	
	
	local mx,my,mz = getElementPosition(medic)
	local patient
	if intended_patient~=nil then -- if a name was specified, use that name
		patient = intended_patient
	else	
		local d1 = 1000000.0
		for index, player in ipairs(getElementsByType("player")) do -- otherwise loop through all players and find the closest one
			if player then
				if player~=medic then
					local x,y,z = getElementPosition(player)
					local d2 = getDistanceBetweenPoints3D(mx,my,mz,x,y,z)
					if d2<d1 then
						d1 = d2
						patient = player
					end
				end
			end
		end
	end		
	
	if not patient then outputChatBox("Couldn't find anyone to heal.",medic) return end -- if no patient was found
	
	local x,y,z = getElementPosition(patient) -- patient must be within 2 units of medic
	if getDistanceBetweenPoints3D(mx,my,mz,x,y,z)>2.0 then
		outputChatBox("Too far from "..getClientName(patient),medic) return
	end
	
	local medic_health = getElementHealth(medic)
	local patient_health = getElementHealth(patient)
	
	if medic_health<2 then outputChatBox("Health too low.",medic) return end -- medic cant kill himself by healing someone
	if patient_health==100 then outputChatBox("There is nothing you can do.",medic) return end -- if patient has full health
	
	local medicine = math.floor((100 - patient_health)/2)
	if (medicine > (medic_health-1)) then medicine = medic_health-1 end
	
	outputChatBox(string.format("Initial health: medic: %.1f patient: %.1f medicine %.1f",medic_health,patient_health,medicine),medic)
	outputChatBox(string.format("Initial health: medic: %.1f patient: %.1f medicine %.1f",medic_health,patient_health,medicine),patient)
--	outputChatBox(string.format("Final health: medic: %.1f patient: %.1f",medic_health-medicine,patient_health+(medicine*2)),medic)
--	outputChatBox(string.format("Final health: medic: %.1f patient: %.1f",medic_health-medicine,patient_health+(medicine*2)),patient)
	
	if medicine<=0.0 then outputChatBox("There is nothing you can do.",medic) return end
	
	setElementHealth(medic,medic_health-medicine)
	setElementHealth(patient,patient_health+(medicine*2))
	
	outputChatBox(string.format("Gave %.2f of health to patient.",medicine),medic)
	outputChatBox(string.format("You were healed by %.2f health.",medicine),patient)	
end

function Plan(player,command,...)
	if command_block==1 then return end
	local team = getElementData(player,"ptpm_team")
	local plan_message = {...}
	if #plan_message == 0 then -- if no arguments were passed (ie: just viewing the plan)
		if ((team==TEAM_PRIMEMINISTER) or (team==TEAM_BODYGUARD) or (team==TEAM_COP)) then -- if they are a 'good guy'
			if plan_active == 1 then -- if there is a plan
				outputChatBox("Plan: "..plan_text,player) return -- show the plan
			else
				outputChatBox("The Prime Minister has not outlined a plan.",player) -- there is no plan
			end
		else
			outputChatBox("You are not allowed to see the plan.",player) return -- 'bad guys' cant see the plan
		end
	else -- if arguments were passed (ie: attempting to set the plan)
		if team==TEAM_PRIMEMINISTER then -- must be prime minister to set the plan
			plan_text = table.concat(plan_message," ") -- format the plan text with all the arguments
			plan_active = 1 -- set the plan to active
			for index, pplayer in ipairs(getElementsByType("player")) do -- loop all players 
				if pplayer then
					local pteam = getElementData(pplayer,"ptpm_team")
					if ((pteam==TEAM_PRIMEMINISTER) or (pteam==TEAM_BODYGUARD) or (pteam==TEAM_COP)) then -- if they are a 'good guy'
						outputChatBox("New plan!",pplayer,255,0,0,true) -- show them the new plan
						outputChatBox("Plan: "..plan_text,pplayer) return
					end
				end
			end
		else
			outputChatBox("Only the Prime Minister can outline a plan.",player)
		end
	end
end

function PrintPlayers(player)
	outputChatBox("Players: "..getPlayerCount(),player)
end

-- returns 1 if  x,y crosses the line on its way to -infinity,y
function LeftIntersect(x,y,x1,y1,x2,y2)
		-- returns 1 if %2 is between %1 and %3 (y1,y,y2)
		if ((tonumber(y1)<=tonumber(y) and tonumber(y)<=tonumber(y2)) or (tonumber(y2)<=tonumber(y) and tonumber(y)<=tonumber(y1))) then
		else return 0 end

		-- x co-ord of point on the line, at height y
		local point = (tonumber(y)-tonumber(y1)) * (tonumber(x2)-tonumber(x1)) / (tonumber(y2)-tonumber(y1)) + tonumber(x1)
		if tonumber(x)>point then return 1
		else return 0 end
end


function IsCoordInPolygon(x,y,xs,ys,num_edges)
		local c = 0
		local j = num_edges-1
		for i = 0,num_edges-1 do
			if i~=0 then j=i-1 end
			if (LeftIntersect(x,y,xs[i],ys[i],xs[j],ys[j])~= 0) then
				c = c+1
			end
		end
		
		if num_edges == 0 then return 1 end
		if ((c%2)==1) then return 1
		else return 0 end
end

function PlayerOutOfBounds(x,y)
	if IsCoordInPolygon(x,y,game_boundary_x,game_boundary_y,game_boundary_count)==1 then
		return false -- within bounds
	end
	return true -- out of bounds
end

function GetElementFromName(player,victim_name)
	if victim_name==nil then return end
	
	local victim_element
	local num_matches = 0
	for index, player in ipairs(getElementsByType("player")) do
		if player then
			local name = getClientName(player)
			if string.find(string.lower(name),string.lower(victim_name))~=nil then
				victim_element = player
				num_matches = num_matches+1
			end
		end
	end
	if num_matches == 0 then
		outputChatBox("No match for \""..victim_name.."\".",player)
		return false
	elseif num_matches == 1 then
		return victim_element
	elseif num_matches > 1 then
		outputChatBox("Too many matches ("..num_matches..") for \""..victim_name.."\".",player)
		return false
	end
end

function OnPlayerStartEnterVehicle(player,seat,jacked)
	if seat==0 then
	    if cant_drive_vehicle[tonumber(getElementData(player,"ptpm_team"))][getVehicleID(source)]==1 then
	        cancelEvent()
	        outputChatBox("You are not qualified to use this vehicle!",player)
	    end
	else
	    if cant_passenger_vehicle[tonumber(getElementData(player,"ptpm_team"))][getVehicleID(source)]==1 then
	        cancelEvent()
	        outputChatBox("You are not qualified to enter this vehicle!",player)
	    end
	end
end
addEventHandler("onVehicleStartEnter",root,OnPlayerStartEnterVehicle )

function OnPlayerVehicleEnter(vehicle,seat,jacked)
	if source==current_pm then pm_fresh = 0 end
	
	local map = current_map
	if getResourceName(map)=="ptpm_air_assault" then
		if getElementData(vehicle,"ptpm_vehicle_fresh")==1 then
			if getVehicleID(vehicle)==476 then -- rustler
				local team = getElementData(vehicle,"ptpm_vehicle_team")
				local x,y,z = getElementPosition(vehicle)
				if team==TEAM_TERROR then -- terror
					setElementPosition(vehicle,x,y,z+math.random(10,50))
					setElementVelocity(vehicle,-4,0,0)
					setVehicleLandingGearDown(vehicle,false)
				elseif team==TEAM_BODYGUARD then -- bguard
					setElementPosition(vehicle,x,y,z+math.random(10,50))
					setElementVelocity(vehicle,-5,0,0)
					setVehicleLandingGearDown(vehicle,false)
				elseif team==TEAM_COP then -- cop
					setElementPosition(vehicle,x,y,z+math.random(10,50))
					setElementVelocity(vehicle,4.8,4.7,0)
					setVehicleLandingGearDown(vehicle,false)
				end
			end
		end
	end
	
	setElementData(vehicle,"ptpm_vehicle_fresh",0)
	
	if respawn_table[vehicle].timer then
		killTimer(respawn_table[vehicle].timer)
		respawn_table[vehicle].timer = nil
	end
end
addEventHandler("onPlayerVehicleEnter",root,OnPlayerVehicleEnter)

function OnPlayerVehicleExit(vehicle,seat,jacker)
	local players_in_car = 0
	for index,player in ipairs(getElementsByType("player")) do
		if player then
			if isPlayerInVehicle(player) and getPlayerOccupiedVehicle(player) == vehicle then
				players_in_car = players_in_car + 1
			end
		end
	end
	if players_in_car == 0 then
		respawn_table[vehicle].timer = setTimer(RespawnVehicle,respawn_table[vehicle].delay,1,vehicle)
	end	
end
addEventHandler("onPlayerVehicleExit",getRootElement(),OnPlayerVehicleExit)


function RespawnVehicle(vehicle)
	respawnVehicle(vehicle)
	setElementData(vehicle,"ptpm_vehicle_fresh",1)
	respawn_table[vehicle].timer = nil
	PlayerVehicleDetach(vehicle)
end

function OnVehicleRespawn(explosion)
	setElementData(source,"ptpm_vehicle_fresh",1)
	PlayerVehicleDetach(source)
end
addEventHandler("onVehicleRespawn",root,OnVehicleRespawn)

function PlayerVehicleDetach(vehicle)
	local elements = getAttachedElements(vehicle)
	if elements then
		for index, element in ipairs(elements) do
			if getElementType(element)=="player" then
				detachElementFromElement(element,vehicle)
				triggerClientEvent(element,"UnstickFromVehicle",root)
			end
		end
	end
end

function PlayerVehicleStickTrigger(stick,vehicle,x,y,z)
	if stick == 1 then -- stick
		attachElementToElement(source,vehicle,x,y,z)
	elseif stick == 0 then -- unstick
		detachElementFromElement(source,vehicle)
	end
end
addEvent("PlayerVehicleStickTrigger",true)
addEventHandler("PlayerVehicleStickTrigger",root,PlayerVehicleStickTrigger)

function SameTeam(team1,team2)
	if (team1==team2 and team1~=TEAM_PSYCHO) then return true end
	if ((team1==TEAM_PRIMEMINISTER and team2==TEAM_BODYGUARD) or (team1==TEAM_BODYGUARD and team2==TEAM_PRIMEMINISTER)) then return true end
	if ((team1==TEAM_PRIMEMINISTER and team2==TEAM_COP) or (team1==TEAM_COP and team2==TEAM_PRIMEMINISTER)) then return true end
	if ((team1==TEAM_BODYGUARD and team2==TEAM_COP) or (team1==TEAM_COP and team2==TEAM_BODYGUARD)) then return true end
	return false
end


function PlayerMapVoteCommand(player,command,...)
	local args = {...}
	if #args == 0 then
		ShowPlayerMapvoteMenuTrigger(player)
	elseif tonumber(args[1])~=nil and tonumber(args[1])>=1 and tonumber(args[1])<=12 then -- if its numerical
		if supported[tonumber(args[1])]==1 then -- if its supported
			PlayerMapVote(player,tonumber(args[1]),getElementData(player,"ptpm_mapvote"),3) -- player mapvote
		end
	else 
		local map = args[1]
		local vote = -1
		if map=="ls_hydra" or map=="ls_h" or map=="lshydra" or map=="lsh" then
			vote = 1
		elseif map=="sf" or map=="sanfierro" or map=="sanf" then
			vote = 2
		elseif map=="desert" or map=="d" then
			vote = 3
		elseif map=="area51" or map=="a51" then
			vote = 4
		elseif map=="lv_obj" or map=="lvobj" or map=="lvo" then
			vote = 5
		elseif map=="air" or map=="air_assault" or map=="airassault" then
			vote = 6
		elseif map=="chiliad" or map=="chilliad" or map=="chill" or map=="chil" then
			vote = 7
		elseif map=="country" or map=="countryside" or map=="cs" then
			vote = 8
		elseif map=="ls" or map=="los_santos" or map=="lossantos" then
			vote = 9
		elseif map=="las_venturas" or map=="lv" or map=="lasventuras" then
			vote = 10
		elseif map=="factory" or map=="fac" then
			vote = 11
		elseif map=="bayside" or map=="bay" then
			vote = 12
		end
		if vote~=-1 and supported[vote]==1 then
			PlayerMapVote(player,vote,getElementData(player,"ptpm_mapvote"),4) -- player mapvote
		end
	end
end

function ShowPlayerMapvoteMenuTrigger(player)
	if (player) then
		triggerClientEvent(player,"ShowPlayerMapvoteMenu",root)
	end	
end

function PlayerMapVote(player,vote,previous_vote,via)
	if vote==previous_vote then return end
	local via_
	if via==1 then via_ = "menu [single digit]"
	elseif via==2 then via_ = "menu [double digit]"
	elseif via==3 then via_ = "command [digit]"
	elseif via==4 then via_ = "command [text]" end
--	outputChatBox("You voted for map # "..vote.." ("..via_..").",player)
	outputChatBox("You voted for map #"..vote..".",player)
	
	setElementData(player,"ptpm_mapvote",vote)
	
	-- update the new scores on every players client
	triggerClientEvent(player,"ResetMapvoteColours",root,vote,previous_vote)
	local vote_table = {0,0,0,0,0,0,0,0,0,0,0,0}
	for index, pplayer in ipairs(getElementsByType("player")) do
		if player then
			local vote_ = tonumber(getElementData(pplayer,"ptpm_mapvote"))
			if vote_~=-1 then
				vote_table[vote_] = vote_table[vote_] + 1
			end	
		end
	end
	triggerClientEvent(root,"UpdateMapVotesInMenu",root,vote_table)
end
addEvent("PlayerMapVote",true)
addEventHandler("PlayerMapVote",root,PlayerMapVote)


function PlayerReclassCommand(player,command,...)
	if command_block==1 then return end
	local args = {...}
	if getElementData(player,"ptpm_team")==3 then outputChatBox("The Prime Minister must use /swapclass.",player) return end
	if #args==0 then
		ClientSpawnMenuTrigger(player)
	else
		local team = args[1]
		local class = -1
		local team_id = -1
		if team=="psycho" or team=="p" or team=="psychopath" then
			local class_info = getElementByID("psychopath")
			local classes = getElementsByType("skin",class_info)
			class = math.random(1,#classes)
			team_id = 1
		elseif team=="terror" or team=="t" or team=="terrorist" then
			local class_info = getElementByID("terrorist")
			local classes = getElementsByType("skin",class_info)
			class = math.random(1,#classes)	
			team_id = 2
		elseif team=="pm" or team=="prime_minister" or team=="primeminister" or team=="prime" then
			local class_info = getElementByID("prime minister")
			local classes = getElementsByType("skin",class_info)
			class = math.random(1,#classes)
			team_id = 3
		elseif team=="bguard" or team=="b" or team=="bodyguard" or team=="bodyg" then
			local class_info = getElementByID("bodyguard")
			local classes = getElementsByType("skin",class_info)
			class = math.random(1,#classes)
			team_id = 4
		elseif team=="cop" or team=="c" then
			local class_info = getElementByID("cop")
			local classes = getElementsByType("skin",class_info)
			class = math.random(1,#classes)
			team_id = 5
		elseif team=="tm" or team=="tmedic" then
			team_id = 2
			local class_info = getElementByID("terrorist")
			local classes = getElementsByType("skin",class_info)			
			for index,the_class in ipairs(classes) do
				if string.find(getElementData(the_class,"type"),"medic") then
					class = index
				end
			end
		elseif team=="bm" or team=="bmedic" then
			team_id = 4
			local class_info = getElementByID("bodyguard")
			local classes = getElementsByType("skin",class_info)	
			for index,the_class in ipairs(classes) do
				if string.find(getElementData(the_class,"type"),"medic") then
					class = index
				end
			end	
		elseif team=="cm" or team=="cmedic" then
			team_id = 5
			local class_info = getElementByID("cop")
			local classes = getElementsByType("skin",class_info)	
			for index,the_class in ipairs(classes) do
				if string.find(getElementData(the_class,"type"),"medic") then
					class = index
				end
			end			
		end
		if class~=-1 then
			SpawnPlayerFunc(player,team_id,class,0)
		end
	end
end


function PlayerCallvoteCommand(player,command,victim_,...)
	local victim = GetElementFromName(player,victim_)
	if victim == false then return end
	
	local admins=ReturnOnlineAdmins()
	if #admins>0 then 
		outputChatBox("Use /report to report a cheater to the admins.",player)
		return
	end
	
	local args = {...}
	if #args==0 then
		outputChatBox("You didnt enter a reason. Usage: /callvote <player> <reason>",player)
		return 
	end
	local reason = table.concat(args," ") 
	if string.len(reason)>60 then
		outputChatBox("Your reason must be less than 60 characters.",player)
		return
	end
	if vote_timer then
		outputChatBox("There is already a vote in progress.",player)
		return
	end
	
	-- begin vote	
	vote_victim = victim
	vote_initiator = player
	vote_reason = reason
	vote_serial = getPlayerSerial(vote_victim)
	vote_victim_name = getClientName(vote_victim)
	
	votes_left = 1 + (getPlayerCount()*5)/10
 	if votes_left==getPlayerCount() then
		votes_left = votes_left - 1
	end
	if votes_left<2 then
		votes_left = 2
	end
	
	votes_left = math.floor(votes_left)

	vote_timer = setTimer(ResetVote,90000,1,1)
	
	-- log the callvote
	local init_serial = getPlayerSerial(vote_initiator)
	local vic_serial = getPlayerSerial(vote_victim)
	if init_serial~=false and vic_serial~=false then
		outputServerLog("CALLVOTE: "..getClientName(vote_initiator).." ("..getClientIP(vote_initiator)..")[account: "..getPlayerUserName(vote_initiator).." [serial: "..init_serial.."]] called a vote against "..vote_victim_name.." ("..getClientIP(vote_victim)..")[account: "..getPlayerUserName(vote_victim).." [serial: "..vic_serial.."]] with the reason: "..vote_reason)
	elseif init_serial==false and vic_serial==false then
		outputServerLog("CALLVOTE: "..getClientName(vote_initiator).."[account: "..getPlayerUserName(vote_initiator).."[serial: INVALID]] called a vote against "..vote_victim_name.." [account: "..getPlayerUserName(vote_victim).." [serial: INVALID]] with the reason: "..vote_reason)
	elseif init_serial~=false and vic_serial==false then
		outputServerLog("CALLVOTE: "..getClientName(vote_initiator).." ("..getClientIP(vote_initiator)..")[account: "..getPlayerUserName(vote_initiator).." [serial: "..init_serial.."]] called a vote against "..vote_victim_name.." [account: "..getPlayerUserName(vote_victim).." [serial: INVALID]] with the reason: "..vote_reason)
	elseif init_serial==false and vic_serial~=false then
		outputServerLog("CALLVOTE: "..getClientName(vote_initiator).."[account: "..getPlayerUserName(vote_initiator).." [serial: INVALID]] called a vote against "..vote_victim_name.." ("..getClientIP(vote_victim)..")[account: "..getPlayerUserName(vote_victim).." [serial: "..vic_serial.."]] with the reason: "..vote_reason)
	end

	triggerClientEvent(root,"UpdateCallvoteMenu",root,getClientName(vote_victim),vote_reason,votes_left)
	triggerClientEvent(root,"ShowCallvoteMenu",root)
end

function ResetVote(reason)
	if isElement(vote_initiator) then
		outputServerLog("CALLVOTE: vote by "..getClientName(vote_initiator).." on "..vote_victim_name.." closed.")
	else
		outputServerLog("CALLVOTE: vote on "..vote_victim_name.." closed.")
	end
	triggerClientEvent(root,"HideCallvoteMenu",root,nil,nil,reason)
	vote_victim = nil
	vote_initiator = nil
	killTimer(vote_timer)
	vote_timer = nil
	votes_left = nil
	vote_reason = nil
	vote_serial = nil
	vote_victim_name = nil
	if reason==1 then
		outputChatBox("Vote closed. Not enough votes.",root)
	elseif reason==2 then
		outputChatBox("Vote closed. Vote successful.",root)
	elseif reason==3 then
		outputChatBox("Vote closed by initiator.",root)
	elseif reason==4 then
		outputChatBox("Vote closed by admin.",root)
	end
	
	for index, player in ipairs(getElementsByType("player")) do
		if player then
			player_callvote_voted[player] = 0
		end
	end
end

function AddVote(player)
	if not vote_timer then
		outputChatBox("There is no vote currently.",player)
		return 
	end	
	if player_callvote_voted[player]==1 then
		outputChatBox("You have already voted.",player)
		return
	end
	
	player_callvote_voted[player] = 1
	votes_left = votes_left - 1
	outputChatBox("Vote cast.",player)
	triggerClientEvent("UpdateCallvoteMenu",root,getClientName(vote_victim),vote_reason,votes_left)
	if votes_left<=0 then
		--kickPlayer(vote_victim,vote_initiator,vote_reason)
		outputServerLog("CALLVOTE: "..getClientName(vote_victim).." voted off the server by "..getClientName(vote_initiator))
		local victim = vote_victim
		local serial = vote_serial
		local name = vote_victim_name
		local reason = vote_reason
		ResetVote(2)
		if isElement(victim) then
			kickPlayer(victim,root,"Voted off server. 10 minute ban.")
			banSerial(serial)
		else 
			banSerial(serial)
			outputChatBox(""..name.." voted off server, 10 minute ban. Reason: "..reason..".",root)
		end
		local index = 1
		while callvote_ban_tracker[index]~=nil do
			index = index+1
		end
		if index > callvote_ban_max then callvote_ban_max = index end
		callvote_ban_tracker[index] = {}
			callvote_ban_tracker[index].serial = serial
			callvote_ban_tracker[index].name = name
			callvote_ban_tracker[index].timer = setTimer(CallvoteUnban,600000,1,serial,index)
	end
end
addEvent("AddVote",true)
addEventHandler("AddVote",getRootElement(),AddVote)

function CallvoteUnban(serial,index)
	unbanSerial(serial)
	outputServerLog("CALLVOTE: "..callvote_ban_tracker[index].name.." ("..serial..") unbanned.")
	callvote_ban_tracker[index].serial = nil
	callvote_ban_tracker[index].timer = nil
	callvote_ban_tracker[index].name = nil
	callvote_ban_tracker[index] = nil
end

function PlayerEndvoteCommand(player,command)
	if vote_timer then
		if vote_initiator==player then
			ResetVote(3)
		elseif (hasObjectPermissionTo(player,"function.kickPlayer",false)) then
			ResetVote(4)
		else
			outputChatBox("You are not the initiator.",player)
			return
		end
	end
end


function OnPlayerPickupPickup(pickup)
--	outputChatBox("PICKUP: type: "..getPickupType(pickup).." weapon: "..getPickupWeapon(pickup),source)
end
addEventHandler("onPlayerPickupUse",root,OnPlayerPickupPickup)
--[[
addEventHandler("onClientLogout",root,
	function (previous,current)
		setAccountData(previous,"ptpm_kills",getElementData(source,"ptpm_kills"))
		setAccountData(previous,"ptpm_deaths",getElementData(source,"ptpm_deaths"))
		setAccountData(previous,"ptpm_pmkills",getElementData(source,"ptpm_pmkills"))
		setAccountData(previous,"ptpm_pmvictory",getElementData(source,"ptpm_pmvictory"))
		
		setAccountData(previous,"ptpm_spawned1",getElementData(source,"ptpm_spawned1"))
		setAccountData(previous,"ptpm_spawned2",getElementData(source,"ptpm_spawned2"))
		setAccountData(previous,"ptpm_spawned3",getElementData(source,"ptpm_spawned3"))
		setAccountData(previous,"ptpm_spawned4",getElementData(source,"ptpm_spawned4"))
		setAccountData(previous,"ptpm_spawned5",getElementData(source,"ptpm_spawned5"))
		
		setAccountData(previous,"ptpm_mapcount1",getElementData(source,"ptpm_mapcount1"))
		setAccountData(previous,"ptpm_mapcount2",getElementData(source,"ptpm_mapcount2"))
		setAccountData(previous,"ptpm_mapcount3",getElementData(source,"ptpm_mapcount3"))
		setAccountData(previous,"ptpm_mapcount4",getElementData(source,"ptpm_mapcount4"))
		setAccountData(previous,"ptpm_mapcount5",getElementData(source,"ptpm_mapcount5"))
		setAccountData(previous,"ptpm_mapcount6",getElementData(source,"ptpm_mapcount6"))
		setAccountData(previous,"ptpm_mapcount7",getElementData(source,"ptpm_mapcount7"))
		setAccountData(previous,"ptpm_mapcount8",getElementData(source,"ptpm_mapcount8"))
		setAccountData(previous,"ptpm_mapcount9",getElementData(source,"ptpm_mapcount9"))
		setAccountData(previous,"ptpm_mapcount10",getElementData(source,"ptpm_mapcount10"))
		setAccountData(previous,"ptpm_mapcount11",getElementData(source,"ptpm_mapcount11"))
		setAccountData(previous,"ptpm_mapcount12",getElementData(source,"ptpm_mapcount12"))
	end)]]

addEventHandler("onClientLogout",root,
	function (previous,current)
		player_admin[source] = false
	end)
	
addEventHandler("onClientLogin",root,
	function (previous,current,auto)
	--	outputChatBox("Successfully logged in.",source)
	
		-- taken from 'admin' resource
		local group = aclGetGroup("Admin")
		if (group) then
			local user = "user."..getAccountName(current)
			for id, object in ipairs(aclGroupListObjects(group)) do
				if (object==user) then
					player_admin[source] = true
				end
			end
		else
			outputChatBox ( "ERROR: Admin group not initialized." )
		end
--[[		local blur = getAccountData(current,"ptpm.blur")
		local acallv = getAccountData(current,"ptpm.callvote.alpha")
		local amapv = getAccountData(current,"ptpm.mapvote.alpha")
		local aset = getAccountData(current,"ptpm.settings.alpha")
		local akey = getAccountData(current,"ptpm.keys.alpha")
		local action1 = getAccountData(current,"ptpm.action1.key")
		local action2 = getAccountData(current,"ptpm.action2.key")
		local vstick = getAccountData(current,"ptpm.stick.key")
		
		setElementData(source,"ptpm_kills",getAccountData(current,"ptpm_kills"))
		setElementData(source,"ptpm_deaths",getAccountData(current,"ptpm_deaths"))
		setElementData(source,"ptpm_pmkills",getAccountData(current,"ptpm_pmkills"))
		setElementData(source,"ptpm_pmvictory",getAccountData(current,"ptpm_pmvictory"))
		
		setElementData(source,"ptpm_spawned1",getAccountData(current,"ptpm_spawned1"))
		setElementData(source,"ptpm_spawned2",getAccountData(current,"ptpm_spawned2"))
		setElementData(source,"ptpm_spawned3",getAccountData(current,"ptpm_spawned3"))
		setElementData(source,"ptpm_spawned4",getAccountData(current,"ptpm_spawned4"))
		setElementData(source,"ptpm_spawned5",getAccountData(current,"ptpm_spawned5"))
		
		setElementData(source,"ptpm_mapcount1",getAccountData(current,"ptpm_mapcount1"))
		setElementData(source,"ptpm_mapcount2",getAccountData(current,"ptpm_mapcount2"))
		setElementData(source,"ptpm_mapcount3",getAccountData(current,"ptpm_mapcount3"))
		setElementData(source,"ptpm_mapcount4",getAccountData(current,"ptpm_mapcount4"))
		setElementData(source,"ptpm_mapcount5",getAccountData(current,"ptpm_mapcount5"))
		setElementData(source,"ptpm_mapcount6",getAccountData(current,"ptpm_mapcount6"))
		setElementData(source,"ptpm_mapcount7",getAccountData(current,"ptpm_mapcount7"))
		setElementData(source,"ptpm_mapcount8",getAccountData(current,"ptpm_mapcount8"))
		setElementData(source,"ptpm_mapcount9",getAccountData(current,"ptpm_mapcount9"))
		setElementData(source,"ptpm_mapcount10",getAccountData(current,"ptpm_mapcount10"))
		setElementData(source,"ptpm_mapcount11",getAccountData(current,"ptpm_mapcount11"))
		setElementData(source,"ptpm_mapcount12",getAccountData(current,"ptpm_mapcount12"))
		
		triggerClientEvent(source,"UpdateSettings",root,false,blur,acallv,amapv,aset,akey,action1,action2,vstick,false,false,false)]]
	end)

function ToggleSettingsWindowTrigger(player)
	local account = getClientAccount(player)
	if isGuestAccount(account) then
		outputChatBox("You must be logged into an account to access your settings.",player) return
	end
	
	triggerClientEvent(player,"ToggleSettingsWindow",root,getAccountData(account,"ptpm.blur"),
															getAccountData(account,"ptpm.callvote.alpha"),
															getAccountData(account,"ptpm.mapvote.alpha"),
															getAccountData(account,"ptpm.settings.alpha"),
															getAccountData(account,"ptpm.keys.alpha"),
															getAccountData(account,"ptpm.action1.key"),
															getAccountData(account,"ptpm.action2.key"),
															getAccountData(account,"ptpm.stick.key"))
end


function UpdatePlayerSettings(blur,acallv,amapv,aset,akey,action1,action2,vstick)
	local account = getClientAccount(source)
	setPlayerBlurLevel(source,blur)
	setAccountData(account,"ptpm.blur",blur)
	setAccountData(account,"ptpm.callvote.alpha",acallv)
	setAccountData(account,"ptpm.mapvote.alpha",amapv)
	setAccountData(account,"ptpm.settings.alpha",aset)
	setAccountData(account,"ptpm.keys.alpha",akey)
	setAccountData(account,"ptpm.action1.key",action1)
	setAccountData(account,"ptpm.action2.key",action2)
	setAccountData(account,"ptpm.stick.key",vstick)
	outputChatBox("Settings updated & saved.",source)
end
addEvent("UpdatePlayerSettings",true)
addEventHandler("UpdatePlayerSettings",root,UpdatePlayerSettings)

function PlayerRegister(player,command,password)
	if password ~= "" and password ~= nil then
		if string.len(password)>=5 then
			local user = string.lower(getClientName(player))
			if getAccount(user) then
				outputChatBox("Account with that username already exists!",player)
			else
				local account = addAccount(user,password)
				if account then
					outputChatBox("Sucessfully registered. Username: '"..user.."' Password: '"..password.."'",player)
					outputChatBox("Use /login to log in and /settings to access your PTPM settings.")
					
					local acc = getAccount(user,password)
					setAccountData(acc,"ptpm.blur","50")
					setAccountData(acc,"ptpm.callvote.alpha","0.5")
					setAccountData(acc,"ptpm.mapvote.alpha","0.8")
					setAccountData(acc,"ptpm.settings.alpha","0.8")
					setAccountData(acc,"ptpm.keys.alpha","0.8")
					setAccountData(acc,"ptpm.action1.key","lshift")
					setAccountData(acc,"ptpm.action2.key","rshift")
					setAccountData(acc,"ptpm.stick.key","insert")
					
					setAccountData(acc,"ptpm_kills",0)
					setAccountData(acc,"ptpm_deaths",0)
					setAccountData(acc,"ptpm_pmkills",0)
					setAccountData(acc,"ptpm_pmvictory",0)
					
					setAccountData(acc,"ptpm_spawned1",0)
					setAccountData(acc,"ptpm_spawned2",0)
					setAccountData(acc,"ptpm_spawned3",0)
					setAccountData(acc,"ptpm_spawned4",0)
					setAccountData(acc,"ptpm_spawned5",0)
					
					setAccountData(acc,"ptpm_mapcount1",0)
					setAccountData(acc,"ptpm_mapcount2",0)
					setAccountData(acc,"ptpm_mapcount3",0)
					setAccountData(acc,"ptpm_mapcount4",0)
					setAccountData(acc,"ptpm_mapcount5",0)
					setAccountData(acc,"ptpm_mapcount6",0)
					setAccountData(acc,"ptpm_mapcount7",0)
					setAccountData(acc,"ptpm_mapcount8",0)
					setAccountData(acc,"ptpm_mapcount9",0)
					setAccountData(acc,"ptpm_mapcount10",0)
					setAccountData(acc,"ptpm_mapcount11",0)
					setAccountData(acc,"ptpm_mapcount12",0)
				else
					outputChatBox("Error creating account.",player)
				end
			end
		else
			outputChatBox("Password must be at least 5 characters.",player)
		end
	else
		outputChatBox("Error creating account, Usage: /register <password>",player)
	end
end

function ChangePassword(oldpass,newpass)
	local account = getAccount(string.lower(getPlayerUserName(source)),oldpass)
	if account then
		SetPassword(account,newpass)
	else
		outputChatBox("Settings: Old password invalid.",source)
	end
end
addEvent("ChangePassword",true)
addEventHandler("ChangePassword",root,ChangePassword)


function SetPassword(account,pass)
	setAccountPassword(account,pass)
end


function PlayerPullPlayer(player,command,helper_,liftee_)
	if command_block==1 then return end
	local helper = GetElementFromName(player,helper_)
	if helper == false then return end
	
	local liftee = GetElementFromName(player,liftee_)
	if liftee == false then return end
	
	if helper == player then outputChatBox("You must select a second person to help you lift.",player) return end
	if liftee == player or liftee==helper then outputChatBox("You cannot lift one of the lifters.",player)
												outputChatBox("You cannot lift one of the lifters.",helper) return end
	
	local px,py,pz = getElementPosition(player)	
	local hx,hy,hz = getElementPosition(helper)
	local lx,ly,lz = getElementPosition(liftee)
	local dist = getDistanceBetweenPoints3D(px,py,pz,hx,hy,hz)
	local diffz = pz-hz
	local centrex,centrey,centrez
	if px>hx then centrex = (math.abs(px-hx)/2)+hx else centrex = (math.abs(px-hx)/2)+px end
	if py>hy then centrey = (math.abs(py-hy)/2)+hy else centrey = (math.abs(py-hy)/2)+py end
	if pz>hz then centrez = (math.abs(pz-hz)/2)+hz else centrez = (math.abs(pz-hz)/2)+pz end
	local range = getDistanceBetweenPoints3D(lx,ly,lz,centrex,centrey,centrez)
	
	if dist>1 and dist<3 then -- distance between 2 lifters
		if diffz>=-0.3 and diffz<=0.3 then -- z difference between lifters
			if range<5 and range>3 then -- if liftee is within range
				setElementPosition(liftee,centrex,centrey,centrez)
				outputChatBox("You were lifted by "..getClientName(player).." and "..getClientName(helper)..".",liftee)
				outputChatBox("You extend your arm and with "..getClientName(helper).."'s help pull "..getClientName(liftee).." up.",player)
				outputChatBox("You extend your arm and with "..getClientName(player).."'s help pull "..getClientName(liftee).." up.",helper)
			else
				if range>5 then
					outputChatBox(getClientName(liftee).." is not within your reach. ("..range..")",player)
					outputChatBox(getClientName(liftee).." is not within your reach. ("..range..")",helper)
				else 
					outputChatBox(getClientName(liftee).." does not need your help. ("..range..")",player)
					outputChatBox(getClientName(liftee).." does not need your help. ("..range..")",helper)	
				end
			end
		else
			outputChatBox("Both lifters must be at the same height. ("..diffz..")",player)
			outputChatBox("Both lifters must be at the same height. ("..diffz..")",helper)
		end
	else
		if dist<1 then
			outputChatBox("You must be further from "..getClientName(helper)..". ("..dist..")",player)
			outputChatBox("You must be further from "..getClientName(player)..". ("..dist..")",helper)		
		else
			outputChatBox("You must be closer to "..getClientName(helper)..". ("..dist..")",player)
			outputChatBox("You must be closer to "..getClientName(player)..". ("..dist..")",helper)
		end
	end
end
	
function GetVelocity(player,command)
	local x,y,z
	if getPlayerOccupiedVehicle(player)~=false then
		x,y,z = getElementVelocity(getPlayerOccupiedVehicle(player))
	else
		x,y,z = getElementVelocity(player)
	end
	outputChatBox("VELOCITY: x: "..x.." y: "..y.." z: "..z,player)
--	outputServerLog("VELOCITY: x: "..x.." y: "..y.." z: "..z)
end	


function Accept(player,command)
	if command_block==1 then return end
	if current_pm~=-1 then
		if player==swapclass_victim then
			local victim_team = getElementData(player,"ptpm_team")
			if victim_team == -1 then outputChatBox("Invalid team.",player) return end
			local victim_class = getElementData(player,"ptpm_class")
			if victim_class == -1 then outputChatBox("Invalid class.",player) return end
			BoundarySafe(current_pm,10)
			BoundarySafe(player,10)
			SpawnPlayerFunc(current_pm,victim_team,victim_class,0)
			SpawnPlayerFunc(player,TEAM_PRIMEMINISTER,1,0)
			textDisplayRemoveObserver(swapclass_display,player)
			swapclass_victim = nil
			outputChatBox(getClientName(player).." accepted your swapclass offer.",current_pm)
		else
			outputChatBox("You have not been sent a swapclass offer.",player)
		end
	else
		outputChatBox("There is no Prime Minister.",player)
	end
end

function Decline(player,command)
	if command_block==1 then return end
	if swapclass_victim==player then
		textDisplayRemoveObserver(swapclass_display,player)
		swapclass_victim = nil
		if current_pm~=-1 then
			outputChatBox(getClientName(player).." declined your swapclass offer.",current_pm)
		end
	else
		outputChatBox("You have not been sent a swapclass offer.",player)
	end
end

function KnockPlayerFromVehicle(player,command,victim)
	if command_block==1 then return end
	local vehicle = getPlayerOccupiedVehicle(player)
	local seat = getPlayerOccupiedVehicleSeat(player)
	local rand = math.random(3)
	
	if player_knock[player]==true then
		if vehicle~=false then
			if seat==0 then
				local elements = getAttachedElements(vehicle)
				if #elements==1 then
					if rand==2 then
						detachElementFromElement(elements[1],vehicle)
						triggerClientEvent(elements[1],"UnstickFromVehicle",root)
						outputChatBox("You reach out and knock "..getClientName(elements[1]).." off your vehicle.",player)
						outputChatBox(getClientName(player).." knocks you off his vehicle.",elements[1])
					else
						outputChatBox("You reach out and try to knock "..getClientName(elements[1]).." off your vehicle, but you miss.",player)
						outputChatBox(getClientName(player).." attempts to knock you off his vehicle but misses. Your adrenaline levels increase.",elements[1])
						triggerClientEvent(elements[1],"ChangeAdrenaline",root,20)
					end
					
				player_knock[player] = false
				setTimer(function()
					player_knock[player] = true
					end,30000,1)
				elseif #elements>1 then
					local victim_element = getElementFromName(player,victim)
					if victim_element==false then return end
					for index, element in ipairs(elements) do
						if getElementType(element)=="player" then
							if element==victim_element then
								if rand==2 then
									detachElementFromElement(victim_element,vehicle)
									triggerClientEvent(victim_element,"UnstickFromVehicle",root)
									outputChatBox("You reach out and knock "..getClientName(victim_element).." off your vehicle.",player)
									outputChatBox(getClientName(player).." knocks you off his vehicle.",victim_element)
									player_knock[player] = false
									setTimer(function()
										player_knock[player] = true
										end,30000,1)
								else
									outputChatBox("You reach out and try to knock "..getClientName(victim_element).." off your vehicle, but you miss.",player)
									outputChatBox(getClientName(player).." attempts to knock you off his vehicle but misses. Your adrenaline levels increase.",victim_element)
									triggerClientEvent(victim_element,"ChangeAdrenaline",root,20)
									player_knock[player] = false
									setTimer(function()
										player_knock[player] = true
										end,30000,1)
								end
							end
						end
					end
				else
					outputChatBox("There is nobody stuck to your vehicle",player)
				end
			else
				outputChatBox("You are not the driver",player)			
			end
		else
			outputChatBox("You are not in a vehicle",player)
		end
	else
		outputChatBox("You must regain full control of the vehicle again before attempting to knock someone off (30 secs)",player)
	end
end

function TellPlayerIntel(player,command)
	if command_block==1 then return end
	if current_pm~=-1 then
		outputChatBox(getClientName(current_pm).." is in "..getElementZoneName(current_pm),player)
	else
		outputChatBox("There is currently no Prime Minister",player)
	end
end

function PrintMapName(player,command)
	if command_block==1 then return end
	outputChatBox("Current map: "..getResourceInfo(current_map, "name"),player)
end

function ReturnOnlineAdmins()
	local admins = {}
	for index, player in ipairs(getElementsByType("player")) do
		if player then	
			if player_admin[player]==true then
				table.insert(admins,player)
			end
		end
	end
	
	return admins
end

function PrintOnlineAdmins(player,command)
	local admins = ReturnOnlineAdmins()
	local admin_names = ""
	for i, player in ipairs (admins) do
		admin_names = admin_names..getClientName(player)..", "
	end
	outputChatBox("Admins: "..admin_names,player)
end

function RestartRound(player,command)
	if player_admin[player]==1 then
		setTimer(OnRoundEnd,1000,1)
		command_block = 1
	end
end


function Commands()
	addCommandHandler("reclass",PlayerReclassCommand)
	addCommandHandler("rc",PlayerReclassCommand)
	addCommandHandler("motd",Motd)
	addCommandHandler("swapclass",PlayerSwapclass)
	addCommandHandler("timeleft",PrintTime)
	addCommandHandler("tl",PrintTime)
	addCommandHandler("pm",PrintPmName)
	addCommandHandler("kill",KillPlayer)
--	addCommandHandler("ward",SetupWardrobeForPlayerClientTrigger)
	addCommandHandler("cam",GetCameraMode)
	addCommandHandler("duty",ExplainRole)
	addCommandHandler("help",PrintHelp)
	addCommandHandler("cmds",PrintHelp)
	addCommandHandler("commands",PrintHelp)
	addCommandHandler("heal",PlayerHealPlayer)
	addCommandHandler("h",PlayerHealPlayer)
	addCommandHandler("plan",Plan)
	addCommandHandler("players",PrintPlayers)
	addCommandHandler("mapvote",PlayerMapVoteCommand)
	addCommandHandler("mv",PlayerMapVoteCommand)
	addCommandHandler("callvote",PlayerCallvoteCommand)
	addCommandHandler("endvote",PlayerEndvoteCommand)
--	addCommandHandler("settings",ToggleSettingsWindowTrigger)
--	addCommandHandler("stats",ToggleSettingsWindowTrigger)
--	addCommandHandler("register",PlayerRegister)
	addCommandHandler("y",Accept)
	addCommandHandler("n",Decline)
	addCommandHandler("knock",KnockPlayerFromVehicle)
	addCommandHandler("intel",TellPlayerIntel)
	addCommandHandler("map",PrintMapName)
	addCommandHandler("admins",PrintOnlineAdmins)
	addCommandHandler("ptpmrestart",RestartRound)

--	addCommandHandler("pull",PlayerPullPlayer)
	addCommandHandler("getvel",GetVelocity)	
--[[
	addCommandHandler("obj",command_obj,false);
	addCommandHandler("getweather",command_getweather,false);
	addCommandHandler("tk",betena,false )
	addCommandHandler("pinfo",betena,false )
	addCommandHandler("vinfo",betena,false )--]]
end 

addEvent("createCrouchObject",true)
function createCrouchObject(crouch)
	if crouch == false then -- create the platform
		local x,y,z = getElementPosition(source)
		crouchObject[source] = createObject(1249,x,y,z+0.4)
		if crouchObject[source]==false then outputChatBox("PLATFORM: not created",source) else outputChatBox("PLATFORM: created",source) end
		local r,g,b = getPlayerNametagColor(source)
		crouchCorona[source] = createMarker(x,y,z+0.3,"arrow",0.5,r,g,b,255)
	--	local at = attachElementToElement(crouchObject[source],source,0,0,0.4)
	--	if at == true then outputChatBox("PLATFORM: attached") else outputChatBox("PLATFORM: not attached") end
	--	outputChatBox("PLATFORM: created",source)
	elseif crouch == true then -- remove the platform
	--	detachElementFromElement(crouchObject[source])
	--	detachElementFromElement(crouchCorona[player])
	--	setElementPosition(crouchCorona[source],0,0,1000)
		local des = destroyElement(crouchObject[source])
		if des == true then outputChatBox("DESTROY: true",source) else outputChatBox("DESTROY: false",source) end
		destroyElement(crouchCorona[source])
		crouchObject[source] = nil
		crouchCorona[source] = nil
		outputChatBox("PLATFORM: destroyed",source)
	end
end
addEventHandler("createCrouchObject",root,createCrouchObject)