SteamVR/Environments/Scripting/flashlight script code full

From Valve Developer Community
< SteamVR‎ | Environments‎ | Scripting
Revision as of 16:50, 3 February 2017 by Mattwood (talk | contribs) (Created page with "<code> --===========================================================================-- -- -- Flashlight Tool Script -- --================================================...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

--===========================================================================--
--
-- Flashlight Tool Script
--
--===========================================================================--

local m_bIsEquipped = false; -- keep track of whether we are equipped or not
local m_hHand = nil; -- keep a handle to the hand that is holding the tool
local m_nHandID = -1; -- keep track of the hand indes that is holding the tool (0==right, 1==left)
local m_hHandAttachment = nil; -- this is the handle to the tool attachment which displays the actual model in the hand
local m_hPlayer = nil; -- handle to the player holding the tool

local m_bFlashlightOn = false; -- keep track of whether the flashlight is on or not
local m_hFlashlightBeam = nil; -- a handle to the flashlight particle beam
local m_particleTrackpad = nil; -- handle to the trackpad particle system
local m_hLight = nil; -- handle to the light entity that actually illuminates the world in front of the flashlight

-- we store off the trackpad position input from the player
local m_flTrackpadX = 0; 
local m_flTrackpadY = 0;

local m_nTotalColors = 0; -- Total number of colors that can be switched between - this gets set on equip
local m_nCurrentColor = 0; -- out current flashlight color

-- this is the table of colors that we can switch between
local m_tLightColors = {};
m_tLightColors[0] = {255, 255, 255} -- white at the center

m_tLightColors[1] = {255, 128, 0} --
m_tLightColors[2] = {255, 0, 0} --
m_tLightColors[3] = {255, 0, 64} -- 

m_tLightColors[4] = {180, 0, 180} --
m_tLightColors[5] = {64, 0, 180} --
m_tLightColors[6] = {0, 0, 255} -- 

m_tLightColors[7] = {0, 180, 180} -- 
m_tLightColors[8] = {0, 255, 128} -- 
m_tLightColors[9] = {0, 255, 0} --

m_tLightColors[10] = {128, 255, 0} -- 
m_tLightColors[11] = {255, 255, 0} --
m_tLightColors[12] = {255, 180, 0} -- 

-- this tores the min and max degrees for picking colors on the trackpad
local m_tColorDegrees= {};
m_tColorDegrees[0]=0;

---------------------------------------------------------------------------
-- SetEquipped
-- this and SetUnequipped are called by code when the tool is picked up and on dropped
---------------------------------------------------------------------------
function SetEquipped( self, pHand, nHandID, pHandAttachment, pPlayer )
	print( "================  SetEquipped() ");
	
	-- if somehow we don'e have a player here, just return out
	if ( pPlayer == nil ) then return; end

	-- store these into our global scope so we can use them in other functions
	m_hHand = pHand;
	m_nHandID = nHandID;
	m_hHandAttachment = pHandAttachment;
	m_hPlayer = pPlayer;
	m_bIsEquipped = true;

	-- create the trackpad particle system
	local particleName = "particles/tool_fx/controller_trackpad_position_dot.vpcf";
	-- the created particle system is now stored in this handle for use elsewhere
	m_particleTrackpad = ParticleManager:CreateParticle(particleName, PATTACH_POINT_FOLLOW, m_hHandAttachment);
	-- set the position to be on the trackpad_center attachment on the tool model
	ParticleManager:SetParticleControlEnt( m_particleTrackpad, 0, m_hHandAttachment, PATTACH_POINT_FOLLOW, "trackpad_center", Vector( 0, 0, 0 ), true );

	-- based on the number of entries in the m_tLightColors table, set the degree values for later use 
	local m_nTotalColors = table.getn(m_tLightColors);
	local flDegreeChunk = 360.0/m_nTotalColors;
	local nMinDegree = 0;
	for i=1,m_nTotalColors do 
		local max = i*flDegreeChunk;
		m_tColorDegrees[i] = max;
		print( "m_tColorDegrees["..i.."] = "..m_tColorDegrees[i] );
	end

	-- call this function once so the position of the newly created particle system is updated right away
	UpdateTrackpadPosition();

	-- this sets up our think function which will run continually
	m_hHand:SetThink( "FlashlightThink", self, 0.0 );

	return true;
end

---------------------------------------------------------------------------
-- SetUnequipped
-- called when the player drops the tool
---------------------------------------------------------------------------
function SetUnequipped()
	print( "================  SetUnequipped() ");

	m_hHand = nil;
	m_nHandID = -1;
	m_hHandAttachment = nil;
	m_hPlayer = nil;
	m_bIsEquipped = false;

	ReleaseFireButton();

	if ( m_particleTrackpad ~= nil ) then
		ParticleManager:DestroyParticle( m_particleTrackpad, true );
		m_particleTrackpad = nil;
	end

	return true;
end

---------------------------------------------------------------------------
-- GetDegrees
-- this is a helper function for getting the degrees of an x and y position on a 2d surface
-- we use this to figure out which color in the color wheel the user is selecting
---------------------------------------------------------------------------
function GetDegrees( x, y )
    local deltaX = 0 - x;
    local deltaY = 0 - y;

   local radAngle = math.atan2(deltaY, deltaX);
   local degreeAngle = radAngle * 180.0 / math.pi;

   return (180.0 - degreeAngle);
end

---------------------------------------------------------------------------
-- Precache
-- Gets called from code when this entity is created
-- Content that this entity uses needs to be precached before it's used
---------------------------------------------------------------------------
function Precache( context )
	--Cache the models
	PrecacheModel("models/props_gameplay/flashlight001.vmdl", context);
	--Cache the particles
	PrecacheParticle("particles/tool_fx/flashlight_thirdperson.vpcf", context);
	PrecacheParticle("particles/tool_fx/flashlight_thirdperson_beamlet.vpcf", context);
	PrecacheParticle("particles/tool_fx/controller_trackpad_position_dot.vpcf", context);
end

---------------------------------------------------------------------------
-- FlashlightThink
-- The frequency at which this think will run is based on the value that it returns
-- Initiated from SetEquipped
---------------------------------------------------------------------------
function FlashlightThink()

	-- if we don't have a hand attachment, that means it's not equipped
	if ( m_hHandAttachment == nil ) then
		-- the tool is probably already dropped, but we call this function to make sure
		-- everything is cleared and reset as if it were dropped normally
		DropTool();
		return nil;
	end
	
	-- get the index of the model attachment on the tool model
	local modelAttachmentIndex = m_hHandAttachment:ScriptLookupAttachment( "flashlight_beam" );
	-- get the position of the attachment that we just got the index for
	local vecStartPos = m_hHandAttachment:GetAttachmentOrigin( modelAttachmentIndex );
	-- get the forward vector of the tool (it needs to be reversed)
	local direction = -m_hHandAttachment:GetForwardVector();
	-- now move 140 units out from our start position in the direction than tool is facing
	local vecEndPos = (vecStartPos+(direction*140));

	-- if we've already created our flashlight beam particle
	if ( m_hFlashlightBeam ~= nil ) then
		-- make sure the point one is attahced to the attachment point
		ParticleManager:SetParticleControlEnt( m_hFlashlightBeam, 1, m_hHandAttachment, PATTACH_POINT_FOLLOW, "flashlight_beam", Vector(0,0,0), true );
		-- and the second point is where we want our end position to be
		-- the particle system draws particles between these two points along that line
		ParticleManager:SetParticleControl( m_hFlashlightBeam, 2, vecEndPos );
	end

	-- enable this to visualize the line created between vecStartPos and vecEndPos
	--DebugDrawLine(vecStartPos, vecEndPos, 0, 255, 0, true, 0.02);

	return 0.01;
end

---------------------------------------------------------------------------
-- called when the player presses the trigger button (from OnHandleInput)
---------------------------------------------------------------------------
function PressFireButton() 
	ToggleFlashlight();
end

---------------------------------------------------------------------------
-- called when the player presses the trigger button (from OnHandleInput)
---------------------------------------------------------------------------
function ReleaseFireButton()
	-- currently nothing happens when the player releases the trigger button
end

---------------------------------------------------------------------------
-- When the player presses the grip button, we drop the tool
---------------------------------------------------------------------------
function DropTool()
	-- make sure we let the code know the trigger has been released
	ReleaseFireButton();
	-- force the flashlight to go off when we release it
	TurnFlashlightOff();
	-- this calls C++ code on the prop tool entity and forces it to be dropped by the player
	thisEntity:ForceDropTool();
	print( "-------------------DropTool" );
end

---------------------------------------------------------------------------
-- Our color changing function
---------------------------------------------------------------------------
function ChangeColor( nNewColor )
	-- if this function was called, but the color we want to 
	-- change to is the same as the one we are on don't do anything'
	-- it prevents code, sounds, etc from running unnecessarily
	if ( m_nLightColor == nNewColor ) then
		return;
	end

	-- store the new color we want to switch to
	m_nLightColor = nNewColor;
	print( "m_nLightColor = "..nNewColor );

	-- if we have a valid flashlight particle beam
	if ( m_hFlashlightBeam ~= nil ) then
		-- tell the particle system that it should use the new color
		ParticleManager:SetParticleControl( m_hFlashlightBeam, 5, Vector( m_tLightColors[m_nLightColor][1], m_tLightColors[m_nLightColor][2], m_tLightColors[m_nLightColor][3] ) );
	end
 
	-- if we have a valid handle to the light entity
	if ( m_hLight ~= nil ) then
		-- tell it to switch to the new light color
		EntFireByHandle( self, m_hLight, "setlightcolor", ""..m_tLightColors[m_nLightColor][1].." "..m_tLightColors[m_nLightColor][2].." "..m_tLightColors[m_nLightColor][3].."", 0 );		
	end

	EmitSoundOn("ui_select", thisEntity);
end

---------------------------------------------------------------------------
-- OnHandleInput
-- Called from C++ code
-- This function recieves input passed from the controller inputs from the player
-- we can capture these inputs and choose to pass them back to be used by another attachment
-- or we can clear them and "swallow" the input here
-- other hand attachments, like the one that lets you teleport around or change your hand gesture
-- use certain inputs from the player. if you want to prevent these actions while you have
-- THIS tool equipped, you need to clear the input after you catch it
---------------------------------------------------------------------------
function OnHandleInput( input )

	-- here are all of the inputs that can be passed from code:
--		IN_USE_HAND0,			-- when the trigger is pressed
--		IN_USE_HAND1,
--		IN_PAD_LEFT_HAND0,		-- when the pad is pressed on the left side
--		IN_PAD_RIGHT_HAND0,		-- when the pad is pressed on the right side
--		IN_PAD_UP_HAND0,		-- when the pad is pressed on the top
--		IN_PAD_DOWN_HAND0,		-- when the pad is pressed on the bottom
--		IN_PAD_LEFT_HAND1,
--		IN_PAD_RIGHT_HAND1,
--		IN_PAD_UP_HAND1,
--		IN_PAD_DOWN_HAND1,
--		IN_MENU_HAND0,
--		IN_MENU_HAND1,
--		IN_GRIP_HAND0,
--		IN_GRIP_HAND1,
--		IN_GRIPANALOG_HAND0,
--		IN_GRIPANALOG_HAND1,
--		IN_PAD_HAND0,			-- when the pad is rpessed anywhere
--		IN_PAD_HAND1,
--		IN_PAD_TOUCH_HAND0,		-- when the pad is touched anywhere
--		IN_PAD_TOUCH_HAND1, 

	-- these are what's passed in
	--input.buttonsDown;
	--input.buttonsPressed;
	--input.buttonsReleased;
	--input.trackpadX;		-- ( -1.0 to 1.0 ) 
	--input.trackpadY;		-- ( -1.0 to 1.0 ) 
	--input.triggerValue;	-- ( 0 to 1.0 )

	local bUpdateTrackpad = false;

	-- get the current position of the player's finger on the track pad on the X axis
	local flTrackpadX = input.trackpadX;
	if ( flTrackpadX ~= 0 and flTrackpadX ~= m_flTrackpadX ) then
		-- if it changed from the last time we got an input change, note it
		m_flTrackpadX = flTrackpadX;
		--print( "m_flTrackpadX = "..m_flTrackpadX );
		-- and let the check down below know we should update the trackpad visuals
		bUpdateTrackpad = true;
	end

	-- get the current position of the player's finger on the track pad on the Y axis
	local flTrackpadY = input.trackpadY;
	if ( flTrackpadY ~= 0 and flTrackpadY ~= m_flTrackpadY ) then
		-- if it changed from the last time we got an input change, note it
		m_flTrackpadY = flTrackpadY;
		--print( "m_flTrackpadY = "..m_flTrackpadY );
		-- and let the check down below know we should update the trackpad visuals
		bUpdateTrackpad = true;
	end

	-- trackpad position has been changed, update the position and color picked
	if ( bUpdateTrackpad ) then
		UpdateTrackpadPosition();
	end

	-- this is lua's ugly version of a ternary operator
	-- we do this because we only care about the input from the hand that is holding us
	-- but you could check input from the other hand if you want
	local nIN_TRIGGER = IN_USE_HAND1; if (m_nHandID == 0) then nIN_TRIGGER = IN_USE_HAND0 end;
	local nIN_GRIP = IN_GRIP_HAND1; if (m_nHandID == 0) then nIN_GRIP = IN_GRIP_HAND0 end;

	-- this checks to see if the TRIGGER has been pressed on this hand
	-- this is only set when the trigger is first pressed
	-- if you want to see if it's HELD, you need to keep track of that yourself
	if ( input.buttonsPressed:IsBitSet( nIN_TRIGGER ) ) then
		print( "TRIGGER is pressed" );
		-- now clear it because we don't want any other tools to do anything with the trigger press
		input.buttonsPressed:ClearBit( nIN_TRIGGER );

		PressFireButton();
	end

	-- this checks if the TRIGGER has just been released
	if ( input.buttonsReleased:IsBitSet( nIN_TRIGGER ) ) then
		print( "TRIGGER is released" );
		-- clear it!
		input.buttonsReleased:ClearBit( nIN_TRIGGER );

		ReleaseFireButton();
	end

	-- checks to see if the GRIP has been pressed this update
	if ( input.buttonsReleased:IsBitSet( nIN_GRIP ) ) then
		print( "GRIP is released" );
		-- if it's pressed, clear the bit!
		input.buttonsReleased:ClearBit( nIN_GRIP );

		-- drop the tool
		DropTool();
	end

	-- we return the input data back to C++ code so other tools can use it
	-- you could always return null if you want this tool to control 100% of the input....
	return input;
end

---------------------------------------------------------------------------
-- Called from OnHandleInput to update the position and color of our trackpad color indicator 
---------------------------------------------------------------------------
function UpdateTrackpadPosition() 

	-- get the degrees of our current trackpad position
	local deg = GetDegrees( m_flTrackpadX, m_flTrackpadY );
	--print( "degrees = "..deg );

	-- get the distance the player's finger is from the center of the trackpad'
	local flDist = math.sqrt( (m_flTrackpadX ^ 2) + (m_flTrackpadY ^ 2) );
	--print( "flDist = "..flDist );
	if ( flDist < 0.24 ) then
		-- if the player fingers is within this amount of the center - they are choosing WHITE
		ChangeColor( 0 );
	else
		-- otherwise, use the degrees we stored earlier to determine which color they want to pick
		local m_nTotalColors = table.getn(m_tLightColors);
		for i=1,m_nTotalColors do 
			local mindegree = m_tColorDegrees[i-1];
			local maxdegree = m_tColorDegrees[i];
			if ( deg >= mindegree and deg < maxdegree ) then
				ChangeColor( i );
				break;
			end		
		end
	end

	-- set the color on the trackpad particle
	ParticleManager:SetParticleControl( m_particleTrackpad, 1, Vector( -m_flTrackpadY, m_flTrackpadX, 0 ) );
	ParticleManager:SetParticleControl( m_particleTrackpad, 2, Vector( m_tLightColors[m_nLightColor][1], m_tLightColors[m_nLightColor][2], m_tLightColors[m_nLightColor][3] ) );

end

---------------------------------------------------------------------------
-- Called as a single toggle function to turn the flashlight on and off
---------------------------------------------------------------------------
function ToggleFlashlight()
	
	if ( m_bFlashlightOn == true ) then
		TurnFlashlightOff()
	else
		TurnFlashlightOn();
	end

	-- FireHapticPulse is what makes the controller rumble
	-- you can pass 0.1, 0.5 or 1 for light, medium and heavy
	m_hHand:FireHapticPulse(1);
end

---------------------------------------------------------------------------
-- TURN ON!
---------------------------------------------------------------------------
function TurnFlashlightOn()

	-- if we don't have a hand holding us, just return
	if ( m_hHand == nil ) then return; end

	-- shouldn't happen, but if we dont have a player, return
	if ( m_hPlayer == nil ) then print( "NO PLAYER!"); return; end

	-- keep trackof the flashlight now being ON
	m_bFlashlightOn = true;

	-- emit a SOUND on thisEntity - just borrow from the drone
	EmitSoundOn("drone_equip", thisEntity);

	-- this may not be working right now
	EntFireByHandle( self, m_hHandAttachment, "Skin", "1", 0 );		

	local modelAttachmentIndex = m_hHandAttachment:ScriptLookupAttachment( "flashlight_beam" );
	local vecStartPost = m_hHandAttachment:GetAttachmentOrigin( modelAttachmentIndex );
	local angAttachment = m_hHandAttachment:GetAttachmentAngles( modelAttachmentIndex );
	local direction = -m_hHandAttachment:GetForwardVector();	
	local vecEndPos = (vecStartPost+(direction*190));

	local particleName = "particles/tool_fx/flashlight_thirdperson.vpcf";
	m_hFlashlightBeam = ParticleManager:CreateParticle(particleName, PATTACH_POINT_FOLLOW, m_hHandAttachment);
	ParticleManager:SetParticleControlEnt( m_hFlashlightBeam, 0, m_hHandAttachment, PATTACH_POINT_FOLLOW, "flashlight_beam", Vector(0,0,0), true );
	ParticleManager:SetParticleControlEnt( m_hFlashlightBeam, 1, m_hHandAttachment, PATTACH_POINT_FOLLOW, "flashlight_beam", Vector(0,0,0), true );
	ParticleManager:SetParticleControl( m_hFlashlightBeam, 2, vecEndPos );
	ParticleManager:SetParticleControl( m_hFlashlightBeam, 5, Vector( m_tLightColors[m_nLightColor][1], m_tLightColors[m_nLightColor][2], m_tLightColors[m_nLightColor][3] ) );

	local lightTable = 
	{
		origin = vecStartPost,
		angles = angAttachment,
		targetname = "light"..thisEntity:entindex(),
		enabled = "1",
		color = ""..m_tLightColors[m_nLightColor][1].." "..m_tLightColors[m_nLightColor][2].." "..m_tLightColors[m_nLightColor][3].." 255",
		brightness = "1.5",
		range = "400",
		castshadows = "1",
		shadowtexturewidth = "64",
		shadowtextureheight = "64",
		style = "0",
		fademindist = "0",
		fademaxdist = "4000",
		bouncescale = "1.0",
		renderdiffuse = "1",
		renderspecular = "1",
		directlight = "2",
		indirectlight = "0",
		attenuation1 = "0.0",
		attenuation2 = "1.0",	
		innerconeangle = "20",
		outerconeangle = "32"
	}
	m_hLight = SpawnEntityFromTableSynchronous( "light_spot", lightTable )
	m_hLight:SetAngles( angAttachment[1], angAttachment[2], angAttachment[3] );
	m_hLight:SetParent(thisEntity, "flashlight_beam")
end

function TurnFlashlightOff()

	m_bFlashlightOn = false;

	EmitSoundOn("drone_equip", thisEntity);

	EntFireByHandle( self, m_hHandAttachment, "Skin", "0", 0 );		

	if ( m_hLight ~= nil ) then
		m_hLight:Destroy();
		m_hLight = nil;
	end
		
	if ( m_hFlashlightBeam ~= nil ) then
		ParticleManager:DestroyParticle( m_hFlashlightBeam, true );
		m_hFlashlightBeam = nil;
	end
end