----------------------------
-- CakeScript (March 29, 2008)
-- by LuaBanana
--
-- Alpha Version
-- player_util.lua
----------------------------

function CAKE.InitPlayers()

	for k, v in pairs( player.GetAll() ) do

		GAMEMODE:PlayerInitialSpawn( v );
		
	end
	
end

function CAKE.Notify(ply, msg)

	if( ply:EntIndex() == 0 ) then
	
		Msg(msg .. "\n");
	
	else

		--ply:PrintMessage(3, msg);
		umsg.Start("AddChat", ply);
		umsg.String( "-- " .. msg );
		umsg.String( "" );
		umsg.Short(2);
		umsg.Vector( Vector(255,255,0) );
		umsg.End();
	end
	
end

function CAKE.DeathMode(ply)

	local mdl = ply:GetModel()
	
	local rag = ents.Create("prop_ragdoll")
	rag:SetModel(mdl)
	rag:SetPos(ply:GetPos())
	rag:SetAngles(ply:GetAngles())
	rag:Spawn()
	
	timer.Simple( 3, FreezeRagdoll, rag );
	
	ply:SetViewEntity(rag);
	
	ply.deathrag = rag;
	
	local n = #DecayingRagdolls + 1
	DecayingRagdolls[n] = ply.deathrag;
	
	ply:SetNWInt("deathmode", 1)
	
	ply.deathtime = 0;
	ply.nextsecond = CurTime() + 1;
	
	local function Decay1()
	
		local rag = DecayingRagdolls[n];
		if(rag != nil and rag:IsValid()) then
		
			local rag2 = ents.Create("prop_ragdoll");
			rag2:SetModel("models/player/corpse1.mdl");
			rag2:SetPos(rag:GetPos());
			rag2:SetAngles(rag:GetAngles());
			rag2:Spawn();
			
			rag:Remove();
			DecayingRagdolls[n] = rag2;
			ply.deathrag = rag2
			
			timer.Simple( 3, FreezeRagdoll, rag2 );
			
			--rag:SetModel("models/player/corpse1.mdl")
		end
		
	end
	
	local function Decay2()
	
		local rag = DecayingRagdolls[n];
		if(rag != nil and rag:IsValid()) then
		
			local rag2 = ents.Create("prop_ragdoll");
			rag2:SetModel("models/player/Charple01.mdl");
			rag2:SetPos(rag:GetPos());
			rag2:SetAngles(rag:GetAngles());
			rag2:Spawn();
			
			rag:Remove();
			DecayingRagdolls[n] = rag2;
			ply.deathrag = rag2
			
			timer.Simple( 3, FreezeRagdoll, rag2 );
			
			--rag:SetModel("models/player/Charple01.mdl")
		end
		
	end
	
	local function Decay3()
	
		local rag = DecayingRagdolls[n];
		if(rag != nil and rag:IsValid()) then
		
			local rag2 = ents.Create("prop_ragdoll");
			rag2:SetModel("models/skeleton/skeleton_whole.mdl");
			rag2:SetPos(rag:GetPos());
			rag2:SetAngles(rag:GetAngles());
			rag2:Spawn();
			
			rag:Remove();
			DecayingRagdolls[n] = rag2;
			ply.deathrag = rag2
			
			timer.Simple( 3, FreezeRagdoll, rag2 );
			
			--rag:SetModel("models/skeleton/skeleton_whole.mdl")
		end
		
	end
	
	local function Decay4()
	
		local rag = DecayingRagdolls[n];
		if(rag != nil and rag:IsValid()) then
			rag:Remove();
		end
		DecayingRagdolls[n] = nil;
		rag = nil;
		
	end
	
	timer.Simple(120, Decay1);
	timer.Simple(180, Decay2);
	timer.Simple(240, Decay3);
	timer.Simple(300, Decay4);
	
end

local meta = FindMetaTable( "Player" );

function meta:GiveItem(class)
	local inv = self:GetField("inventory") or {};
	table.insert(inv,class);
	self:SetField("inventory",inv,true);
	self:RefreshInventory();
	
end

function meta:TakeItem(class)
	local inv = self:GetField("inventory") or {};
	
	for k, v in pairs(inv) do
		if(v == class) then
			inv[k] = nil;
			self:SetField("inventory", inv, true);
			self:RefreshInventory();
			
			-- usefullness: its over 9000!!! what 9000?
			return true;
		end
	end
	
	-- this makes this function SOO much more useful
	return false;
	
end

function meta:ClearInventory()
	umsg.Start("clearinventory", self)
	umsg.End();
end

function meta:RefreshInventory()
	self:ClearInventory()
	
	for k, v in pairs(self:GetField("inventory") or {}) do
		umsg.Start("addinventory", self);
			umsg.String(ItemData[v].Name);
			umsg.String(ItemData[v].Class);
			umsg.String(ItemData[v].Description);
			umsg.String(ItemData[v].Model);
		umsg.End();
	end
end

function meta:ClearBusiness()
	umsg.Start("clearbusiness", self)
	umsg.End();
end

function meta:RefreshBusiness()
	self:ClearBusiness()
	
	for k, v in pairs(ItemData) do
		if(v.Purchaseable) then
			umsg.Start("addbusiness", self);
				umsg.String(v.Name);
				umsg.String(v.Class);
				umsg.String(v.Description);
				umsg.String(v.Model);
				umsg.Long(v.Price);
			umsg.End();
		end
	end
end

function meta:HandleStunHit(attacker, hitgroup, apprehend)
	local basedmg = 35;
	local mul = 1
	if(!apprehend) then
		mul = mul * 0.1 -- Don't do alot of damage.
	end
	local newdmg = basedmg * mul * 1
	self:SetNWFloat("conscious", math.Clamp(self:GetNWFloat("conscious") - newdmg, 0, 100))
	if(self:GetNWFloat("conscious") >= 0) then
		self:Knockout()
		CAKE.DayLog(attacker:Name() .. " [" .. attacker:SteamID() .. "] knocked out " .. self:Name() .. " [" .. self:SteamID() .. "]");
		local function wat()
			self:Wakeup()
		end
		timer.Simple(30, wat)
	end
	self:ViewPunch( Angle( newdmg, 0, 0 ) )
end
	
function meta:Knockout()

	if( !self:IsValid() ) then
		return;
	end

	-- Lets turn the player into a ragdoll and set isko
	local rag = ents.Create("prop_ragdoll");
	rag:SetModel(self:GetModel());
	rag:SetPos(self:GetPos());
	rag:SetAngles(self:GetAngles());
	rag:Spawn();
	rag:SetNWInt("playerragdoll", 1);
	rag:SetNWInt("player", self:EntIndex());
	rag:SetNWInt("playerragdoll", 1);
	
	self:SelectWeapon("hands");
	
	if( self:GetNWInt( "holstered" ) == 0 ) then
		self:ConCommand( "rp_toggleholster" );
	end
	
	self:SetNWInt("ragdoll", rag:EntIndex());
	self:SetNWInt("ko", 1);
	self:Spectate( OBS_MODE_CHASE );
	self:SpectateEntity( rag );
	self:SetNotSolid(true);
	self:SetColor(Color(255,255,255,0));
	if(self:GetActiveWeapon():IsValid()) then
		self:GetActiveWeapon():SetColor(255,255,255,0);
	end
	
	timer.Simple( 3, FreezeRagdoll, rag );
end

function meta:Wakeup()
	-- Lets wake them up from their ragdoll state
	local rag = ents.GetByIndex(self:GetNWInt("ragdoll"));
	if(rag != nil and rag:IsValid()) then
	
		local pos = rag:GetPos()
		pos.z = pos.z + 10
		self:SetParent()
		rag:Remove()
		self:Spectate( OBS_MODE_NONE )
		self:Spawn()
		self:SetPos(pos)
	else
		self:Spawn()
	end
	self:SetNWInt("ko", 0)
	self:SetNWInt("ragdoll", 0)
	self:UnLock()
	self:SetNotSolid(false)
	self:SetColor(255,255,255,255)
end

-- Taco code with modification
function meta:HandlePunch( attacker, hitgroup )

	self:ViewPunch( Vector( -7, 0, 0 ) );

	local dmgmul = 1;
	local blocking = false;
	
	if( self:GetActiveWeapon():GetClass() == "hands" ) then
	
		if( self:GetActiveWeapon():GetNWBool( "ironsights" ) ) then
		
			blocking = true;
			
		end
		
	end
	
--	local canblur = false;
	
	if( hitgroup == HITGROUP_HEAD ) then
	
		if( not blocking ) then
			dmgmul = 1.9;
--			canblur = true;
		else
			dmgmul = .35;
		end
	
	elseif( hitgroup == HITGROUP_CHEST ) then
	
		if( not blocking ) then
			dmgmul = 1.45;
--			canblur = true;
		else
			dmgmul = .2;
		end
	
	elseif( hitgroup == HITGROUP_STOMACH ) then
	
		if( not blocking ) then
			dmgmul = 1.45;
--			canblur = true;
		else
			dmgmul = .25;
		end
	
	end
	
	-- base damage 10, with up to +10 * multiplier
	local dmg = 10 + 10 * ( attacker:GetNWFloat( "stats.str" ) / 100 ) * dmgmul;
	-- at max the damage can be reduced by 1/3
	dmg = dmg - dmg * ( self:GetNWFloat( "stats.end" ) / 300 );

--[[	
	if( dmg >= 20 and canblur ) then
	
		umsg.Start( "DoBlurHit", self );
			umsg.Float( .5 );
		umsg.End();
	
	end
]]--	
	
	self:SetHealth( math.Clamp( self:Health() - dmg, 0, 100 ) );
	
--	self:SetNWFloat( "conscious", math.Clamp( self:GetNWFloat( "conscious" ) - dmg * .28, 0, 100 ) );
	
	theDice = math.Rand(0, self:GetNWFloat("stats.end") * 3 );
	if ( theDice == 0 ) then
	
		self:SetNWFloat("stats.end", math.Clamp( self:GetNWFloat("stats.end") + 1,0,100) );
		--	self:RaiseEnduranceStat();
	end

	--[[
	local stat = attacker:GetNWFloat( "stat.Strength" );
	local amt = 0;
	
	if( stat < 17 ) then
		amt = .01;
	elseif( stat < 30 ) then
		amt = .038;
	elseif( stat < 50 ) then
		amt = .025;
	elseif( stat < 75 ) then
		amt = .02;
	elseif( stat < 85 ) then
		amt = .014;
	elseif( stat < 100 ) then
		amt = .001;
	end	
	
	if( stat > 55 ) then
		amt = amt * .6;
	end
	
	attacker:SetNWFloat( "stat.Strength", stat + math.Clamp( amt * .25, .0001, 1 ) );
	]]--
	
end

--Garry's statue tool code
function FreezeRagdoll( ent )

	if( ent:GetTable().StatueInfo ) then
		return;
	end
 	 
 	ent:GetTable().StatueInfo = {} 
 	ent:GetTable().StatueInfo.Welds = {} 
 	 
 	local bones = ent:GetPhysicsObjectCount() 
 	 
 	local forcelimit = 0 
 	 
 	// Weld each physics object together 
 	for bone=1, bones do 
 	 
 		local bone1 = bone - 1 
 		local bone2 = bones - bone 
 		 
 		// Don't do identical two welds 
 		if ( !ent:GetTable().StatueInfo.Welds[bone2] ) then 
 		 
 			local constraint1 = constraint.Weld( ent, ent, bone1, bone2, forcelimit ) 
 			 
 			if ( constraint1 ) then 
 			 
 				ent:GetTable().StatueInfo.Welds[bone1] = constraint1 
 			 
 			end 
 			 
 		end 
 		 
 		local constraint2 = constraint.Weld( ent, ent, bone1, 0, forcelimit ) 
 		 
 		if ( constraint2 ) then 
 		 
 			ent:GetTable().StatueInfo.Welds[bone1+bones] = constraint2 
 		 
 		end 
 		 
 	end 

end


function meta:TryDoorRam()

	if( self:GetNWInt( "ko" ) > 1 or self:GetNWInt( "tiedup" ) == 1 ) then
		return;
	end

  	if( CurTime() - self:GetNWInt( "LastDoorKick" ) > 1.7 ) then

		if( not self:OnGround() ) then return; end

		if( self:GetNWInt( "holstered" ) == 1 ) then
		
			--self:PrintMessage( 3, "Need to be unholstered" );
			return;
		
		end
		
		local trent = self:GetEyeTrace().Entity;
		
		if( trent:IsValid() and CAKE.IsDoor(trent) and trent:GetNWInt( "doorstate" ) ~= 7  ) then
		
			self:SetNWInt( "LastDoorKick", CurTime() );
		
			if( trent:GetPos():Distance( self:GetPos() ) > 65 ) then
			
				trent:EmitSound( Sound(  "physics/wood/wood_box_impact_hard3.wav" ) );
			
				if( SERVER ) then
				
					self:ViewPunch( Angle( -25, 0, 0 ) );
					self:SetVelocity( Vector( self:GetAimVector().x, self:GetAimVector().y, 0 ) * 500 );
					
					local dounlock = false;

					if( math.random( 1, 5 ) == 2 ) then
						dounlock = true;
					end
					
					if( dounlock ) then
					
						trent:Fire( "unlock", "", 0 );
						self:ConCommand( "+use\n" );
						timer.Simple( .1, self.ConCommand, self, "-use\n" );
					end
				end
			else
				self:PrintMessage( 3, "Too close to door" );
			end
			
		end
		
	end
	
end