Skip to content

Instantly share code, notes, and snippets.

@NightlyNexus
Created September 17, 2021 01:10
Show Gist options
  • Save NightlyNexus/b008933c0c73ad609c7000ee11513746 to your computer and use it in GitHub Desktop.
Save NightlyNexus/b008933c0c73ad609c7000ee11513746 to your computer and use it in GitHub Desktop.
A script for the Valve flashlight, meant for VR. This fixes bugs, adds some small features, and cleans up the code from the sample here: https://developer.valvesoftware.com/wiki/SteamVR/Environments/Scripting/flashlight_script_code_full
-- Disable this flag to remove the glow particle around the flashlight's lens.
local enableGlow = true;
local glowParticle;
local lightTable = {
classname = "light_spot",
targetname = "light" .. thisEntity:entindex(),
enabled = 0,
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"
}
local isEquipped = false;
local holdingHand;
local holdingHandId = -1; -- 0 is right hand. 1 is the left hand.
local handAttachment;
local player;
local flashlightOn = false;
local particleTrackpad;
local lightEntity;
local trackpadX = 0.0;
local trackpadY = 0.0;
local lightColorsIndex = 13; -- Start at white.
local lightColors = {};
lightColors[1] = { 255, 128, 0 };
lightColors[2] = { 255, 0, 0 };
lightColors[3] = { 255, 0, 64 };
lightColors[4] = { 180, 0, 180 };
lightColors[5] = { 64, 0, 180 };
lightColors[6] = { 0, 0, 255 };
lightColors[7] = { 0, 180, 180 };
lightColors[8] = { 0, 255, 128 };
lightColors[9] = { 0, 255, 0 };
lightColors[10] = { 128, 255, 0 };
lightColors[11] = { 255, 255, 0 };
lightColors[12] = { 255, 180, 0 };
lightColors[13] = { 255, 255, 255 };
local colorWheelCount = 12; -- White is at the center of the wheel.
local colorWheelMaxDegrees = {};
local equippedStartTime = 0;
function SetEquipped(self, pHand, nHandID, pHandAttachment, pPlayer)
holdingHand = pHand;
holdingHandId = nHandID;
handAttachment = pHandAttachment;
player = pPlayer;
isEquipped = true;
equippedStartTime = Time();
local trackpadParticleName = "particles/tool_fx/controller_trackpad_position_dot.vpcf";
particleTrackpad = ParticleManager:CreateParticle(trackpadParticleName, PATTACH_POINT_FOLLOW, handAttachment);
ParticleManager:SetParticleControlEnt(particleTrackpad, 0, handAttachment, PATTACH_POINT_FOLLOW, "trackpad_center", Vector(0, 0, 0), true);
local degreeChunk = 360.0 / colorWheelCount;
for i = 1, colorWheelCount do
local maxDegree = i * degreeChunk;
colorWheelMaxDegrees[i] = maxDegree;
end
if (lightEntity == nil) then
lightEntity = SpawnEntityFromTableSynchronous(lightTable.classname, lightTable);
end
lightEntity:SetParent(handAttachment, "flashlight_beam");
lightEntity:SetLocalOrigin(Vector(0, 0, 0));
lightEntity:SetLocalAngles(0, 0, 0);
if (flashlightOn) then
EntFireByHandle(self, handAttachment, "Skin", "1", 0);
end
ParticleManager:SetParticleControl(particleTrackpad, 1, Vector(-trackpadY, trackpadX, 0));
ParticleManager:SetParticleControl(particleTrackpad, 2, Vector(lightColors[lightColorsIndex][1], lightColors[lightColorsIndex][2], lightColors[lightColorsIndex][3]));
EntFireByHandle(self, lightEntity, "setlightcolor", "" .. lightColors[lightColorsIndex][1] .. " " .. lightColors[lightColorsIndex][2] .. " " .. lightColors[lightColorsIndex][3] .. "", 0);
if (enableGlow) then
if (flashlightOn) then
ParticleManager:DestroyParticle(glowParticle, true);
createGlowParticle(handAttachment);
end
holdingHand:SetThink("FlashlightThink", self, 0.0);
end
return true;
end
function SetUnequipped()
holdingHand = nil;
holdingHandId = -1;
handAttachment = nil;
player = nil;
isEquipped = false;
lightEntity:SetParent(thisEntity, "flashlight_beam");
if (particleTrackpad ~= nil) then
ParticleManager:DestroyParticle(particleTrackpad, true);
particleTrackpad = nil;
end
if (enableGlow and flashlightOn) then
ParticleManager:DestroyParticle(glowParticle, true);
createGlowParticle(thisEntity);
end
return true;
end
---------------------------------------------------------------------------
-- Get the degrees of an x and y position on a two-dimensional surface.
---------------------------------------------------------------------------
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
function Precache(context)
PrecacheModel("models/props_gameplay/flashlight001.vmdl", context);
PrecacheParticle("particles/tool_fx/controller_trackpad_position_dot.vpcf", context);
if (enableGlow) then
PrecacheParticle("particles/tool_fx/flashlight_thirdperson.vpcf", context);
end
end
function ChangeColor(newLightColorsIndex)
if (lightColorsIndex == newLightColorsIndex) then
return ;
end
lightColorsIndex = newLightColorsIndex;
if (enableGlow and flashlightOn) then
ParticleManager:SetParticleControl(glowParticle, 5, Vector(lightColors[lightColorsIndex][1], lightColors[lightColorsIndex][2], lightColors[lightColorsIndex][3]));
end
EntFireByHandle(self, lightEntity, "setlightcolor", "" .. lightColors[lightColorsIndex][1] .. " " .. lightColors[lightColorsIndex][2] .. " " .. lightColors[lightColorsIndex][3] .. "", 0);
EmitSoundOn("ui_select", thisEntity);
end
function OnHandleInput(input)
local holdingHandIN_TRIGGER = IN_USE_HAND1;
if (holdingHandId == 0) then
holdingHandIN_TRIGGER = IN_USE_HAND0
end
local holdingHandIN_GRIP = IN_GRIP_HAND1;
if (holdingHandId == 0) then
holdingHandIN_GRIP = IN_GRIP_HAND0
end
local holdingHandIN_PAD_TOUCH_HAND = IN_PAD_TOUCH_HAND1;
if (holdingHandId == 0) then
holdingHandIN_PAD_TOUCH_HAND = IN_PAD_TOUCH_HAND0
end
if (input.buttonsDown:IsBitSet(holdingHandIN_PAD_TOUCH_HAND)) then
local updateTrackpad = false;
local currentTrackpadX = input.trackpadX;
if (currentTrackpadX ~= trackpadX) then
trackpadX = currentTrackpadX;
updateTrackpad = true;
end
local currentTrackpadY = input.trackpadY;
if (currentTrackpadY ~= trackpadY) then
trackpadY = currentTrackpadY;
updateTrackpad = true;
end
if (updateTrackpad) then
UpdateTrackpadPosition();
end
end
if (input.buttonsPressed:IsBitSet(holdingHandIN_TRIGGER)) then
input.buttonsPressed:ClearBit(holdingHandIN_TRIGGER);
-- Add a delay to prevent the flashlight from turning on when picked up with the trigger.
if (Time() > equippedStartTime + 0.2) then
ToggleFlashlight();
end
end
if (input.buttonsReleased:IsBitSet(holdingHandIN_TRIGGER)) then
input.buttonsReleased:ClearBit(holdingHandIN_TRIGGER);
end
if (input.buttonsReleased:IsBitSet(holdingHandIN_GRIP)) then
input.buttonsReleased:ClearBit(holdingHandIN_GRIP);
thisEntity:ForceDropTool();
end
return input;
end
function UpdateTrackpadPosition()
local degree = GetDegrees(trackpadX, trackpadY);
local distance = math.sqrt((trackpadX ^ 2) + (trackpadY ^ 2));
if (distance < 0.24) then
-- The center of the trackpad is the white selection.
ChangeColor(13);
else
local minDegree = 0
for i = 1, colorWheelCount do
local maxDegree = colorWheelMaxDegrees[i];
if (degree >= minDegree and degree < maxDegree) then
ChangeColor(i);
break ;
end
minDegree = maxDegree;
end
end
ParticleManager:SetParticleControl(particleTrackpad, 1, Vector(-trackpadY, trackpadX, 0));
ParticleManager:SetParticleControl(particleTrackpad, 2, Vector(lightColors[lightColorsIndex][1], lightColors[lightColorsIndex][2], lightColors[lightColorsIndex][3]));
end
function ToggleFlashlight()
if (flashlightOn) then
TurnFlashlightOff()
else
TurnFlashlightOn();
end
holdingHand:FireHapticPulse(1); -- 1 is the heavy rumble.
end
function TurnFlashlightOn()
flashlightOn = true;
-- Borrow the drone sound.
EmitSoundOn("drone_equip", thisEntity);
EntFireByHandle(self, handAttachment, "Skin", "1", 0);
EntFireByHandle(self, thisEntity, "Skin", "1", 0);
EntFireByHandle(self, lightEntity, "TurnOn", "", 0);
if (enableGlow) then
createGlowParticle(handAttachment);
end
end
function TurnFlashlightOff()
flashlightOn = false;
-- Borrow the drone sound.
EmitSoundOn("drone_equip", thisEntity);
EntFireByHandle(self, handAttachment, "Skin", "0", 0);
EntFireByHandle(self, thisEntity, "Skin", "0", 0);
EntFireByHandle(self, lightEntity, "TurnOff", "", 0);
if (enableGlow) then
ParticleManager:DestroyParticle(glowParticle, true);
glowParticle = nil;
end
end
function createGlowParticle(owningEntity)
local modelAttachmentIndex = owningEntity:ScriptLookupAttachment("flashlight_beam");
local vecStartPos = owningEntity:GetAttachmentOrigin(modelAttachmentIndex);
local direction = -owningEntity:GetForwardVector();
local vecEndPos = vecStartPos + (direction * 140);
local glowParticleName = "particles/tool_fx/flashlight_thirdperson.vpcf";
glowParticle = ParticleManager:CreateParticle(glowParticleName, PATTACH_POINT_FOLLOW, owningEntity);
ParticleManager:SetParticleControlEnt(glowParticle, 1, owningEntity, PATTACH_POINT_FOLLOW, "flashlight_beam", Vector(0, 0, 0), true);
ParticleManager:SetParticleControl(glowParticle, 2, vecEndPos);
ParticleManager:SetParticleControl(glowParticle, 5, Vector(lightColors[lightColorsIndex][1], lightColors[lightColorsIndex][2], lightColors[lightColorsIndex][3]));
end
function FlashlightThink()
if (flashlightOn) then
local owningEntity = thisEntity;
if (isEquipped) then
owningEntity = handAttachment;
end
local modelAttachmentIndex = owningEntity:ScriptLookupAttachment("flashlight_beam");
local vecStartPos = owningEntity:GetAttachmentOrigin(modelAttachmentIndex);
local direction = -owningEntity:GetForwardVector();
local vecEndPos = vecStartPos + (direction * 140);
ParticleManager:SetParticleControlEnt(glowParticle, 1, owningEntity, PATTACH_POINT_FOLLOW, "flashlight_beam", Vector(0, 0, 0), true);
ParticleManager:SetParticleControl(glowParticle, 2, vecEndPos);
end
return 0.01;
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment