mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
1235 lines
31 KiB
Lua
1235 lines
31 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
local BUILDER, PART = pac.PartTemplate("base")
|
|
|
|
PART.ClassName = "proxy"
|
|
|
|
PART.ThinkTime = 0
|
|
PART.Group = 'modifiers'
|
|
PART.Icon = 'icon16/calculator.png'
|
|
|
|
BUILDER:StartStorableVars()
|
|
|
|
BUILDER:SetPropertyGroup("generic")
|
|
BUILDER:GetSet("VariableName", "", {enums = function(part)
|
|
local part = part:GetTarget()
|
|
if not part:IsValid() then return end
|
|
local tbl = {}
|
|
for _, info in pairs(part:GetProperties()) do
|
|
if info.key == "UniqueID" then goto CONTINUE end
|
|
|
|
local T = type(info.get())
|
|
if T == "number" or T == "Vector" or T == "Angle" or T == "boolean" then
|
|
tbl[info.key] = info.key
|
|
end
|
|
::CONTINUE::
|
|
end
|
|
|
|
return tbl
|
|
end})
|
|
|
|
BUILDER:GetSet("RootOwner", false)
|
|
BUILDER:GetSetPart("TargetPart")
|
|
BUILDER:GetSetPart("OutputTargetPart", {hide_in_editor = true})
|
|
BUILDER:GetSet("AffectChildren", false)
|
|
BUILDER:GetSet("Expression", "")
|
|
|
|
BUILDER:SetPropertyGroup("easy setup")
|
|
BUILDER:GetSet("Input", "time", {enums = function(part) return part.Inputs end})
|
|
BUILDER:GetSet("Function", "sin", {enums = function(part) return part.Functions end})
|
|
BUILDER:GetSet("Axis", "")
|
|
BUILDER:GetSet("Min", 0)
|
|
BUILDER:GetSet("Max", 1)
|
|
BUILDER:GetSet("Offset", 0)
|
|
BUILDER:GetSet("InputMultiplier", 1)
|
|
BUILDER:GetSet("InputDivider", 1)
|
|
BUILDER:GetSet("Pow", 1)
|
|
|
|
BUILDER:SetPropertyGroup("behavior")
|
|
BUILDER:GetSet("Additive", false)
|
|
BUILDER:GetSet("PlayerAngles", false)
|
|
BUILDER:GetSet("ZeroEyePitch", false)
|
|
BUILDER:GetSet("ResetVelocitiesOnHide", true)
|
|
BUILDER:GetSet("VelocityRoughness", 10)
|
|
|
|
BUILDER:EndStorableVars()
|
|
|
|
-- redirect
|
|
function PART:SetOutputTargetPart(part)
|
|
if not part:IsValid() then return end
|
|
self.SetOutputTargetPartUID = ""
|
|
self:SetTargetPart(part)
|
|
end
|
|
|
|
function PART:GetPhysicalTarget()
|
|
local part = self:GetTargetPart()
|
|
|
|
if part:IsValid() then
|
|
return part
|
|
end
|
|
|
|
local parent = self:GetParent()
|
|
|
|
while not parent.GetWorldPosition or parent:GetWorldPosition():IsZero() do
|
|
if not parent.Parent:IsValid() then break end
|
|
parent = parent.Parent
|
|
end
|
|
|
|
if not parent.GetWorldPosition then
|
|
local owner = parent:GetOwner()
|
|
if owner:IsValid() then
|
|
return owner
|
|
end
|
|
end
|
|
|
|
return parent
|
|
end
|
|
|
|
function PART:GetTarget()
|
|
local part = self:GetTargetPart()
|
|
|
|
if part:IsValid() then
|
|
return part
|
|
end
|
|
|
|
return self:GetParent()
|
|
end
|
|
|
|
function PART:SetVariableName(str)
|
|
self.VariableName = str
|
|
end
|
|
|
|
function PART:GetNiceName()
|
|
if self:GetVariableName() == "" then
|
|
return self.ClassName
|
|
end
|
|
|
|
local target
|
|
|
|
if self.AffectChildren then
|
|
target = "children"
|
|
else
|
|
local part = self:GetTarget()
|
|
if part:IsValid() then
|
|
target = part:GetName()
|
|
end
|
|
end
|
|
|
|
local axis = self:GetAxis()
|
|
if axis ~= "" then
|
|
axis = "." .. axis
|
|
end
|
|
|
|
return (target or "?") .. "." .. pac.PrettifyName(self:GetVariableName()) .. axis .. " = " .. (self.debug_var or "?")
|
|
end
|
|
|
|
function PART:Initialize()
|
|
self.vec_additive = {}
|
|
self.next_vel_calc = 0
|
|
end
|
|
|
|
PART.Functions =
|
|
{
|
|
none = function(n) return n end,
|
|
sin = math.sin,
|
|
cos = math.cos,
|
|
tan = math.tan,
|
|
abs = math.abs,
|
|
mod = function(n, s) return n%s.Max end,
|
|
sgn = function(n) return n>0 and 1 or n<0 and -1 or 0 end,
|
|
}
|
|
|
|
local FrameTime = FrameTime
|
|
|
|
function PART:CalcVelocity()
|
|
self.last_vel = self.last_vel or Vector()
|
|
self.last_vel_smooth = self.last_vel_smooth or self.last_vel or Vector()
|
|
|
|
self.last_vel_smooth = (self.last_vel_smooth + (self.last_vel - self.last_vel_smooth) * FrameTime() * math.max(self.VelocityRoughness, 0.1))
|
|
end
|
|
|
|
function PART:GetVelocity(part)
|
|
local pos
|
|
|
|
if part.GetWorldPosition then
|
|
pos = part:GetWorldPosition()
|
|
else
|
|
if IsEntity(part) then
|
|
pos = part:GetPos()
|
|
elseif part:GetOwner():IsValid() then
|
|
pos = part:GetOwner():GetPos()
|
|
end
|
|
end
|
|
|
|
local time = pac.RealTime
|
|
|
|
if self.next_vel_calc < time then
|
|
self.next_vel_calc = time + 0.1
|
|
self.last_vel = (self.last_pos or pos) - pos
|
|
self.last_pos = pos
|
|
end
|
|
|
|
return self.last_vel_smooth / 5
|
|
end
|
|
|
|
function PART:CalcEyeAngles(ent)
|
|
local ang = self.PlayerAngles and ent:GetAngles() or ent:EyeAngles()
|
|
|
|
if self.ZeroEyePitch then
|
|
ang.p = 0
|
|
end
|
|
|
|
return ang
|
|
end
|
|
|
|
local function try_viewmodel(ent)
|
|
return ent == pac.LocalViewModel and pac.LocalPlayer or ent
|
|
end
|
|
|
|
local function get_owner(self)
|
|
if self.RootOwner then
|
|
return try_viewmodel(self:GetRootPart():GetOwner())
|
|
else
|
|
return try_viewmodel(self:GetOwner())
|
|
end
|
|
end
|
|
|
|
PART.Inputs = {}
|
|
|
|
PART.Inputs.property = function(self, property_name, field)
|
|
|
|
local part = self.TargetEntity:IsValid() and self.TargetEntity or self:GetParent()
|
|
|
|
if part:IsValid() and part.GetProperty and property_name then
|
|
local v = part:GetProperty(property_name)
|
|
|
|
local T = type(v)
|
|
|
|
if T == "Vector" or T == "Angle" then
|
|
if field and v[field] then
|
|
return v[field]
|
|
else
|
|
return v[1],v[2],v[3]
|
|
end
|
|
elseif T == "boolean" then
|
|
return v and 1 or 0
|
|
elseif T == "number" then
|
|
return v
|
|
end
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.owner_position = function(self)
|
|
local owner = get_owner(self)
|
|
|
|
if owner:IsValid() then
|
|
local pos = owner:GetPos()
|
|
|
|
return pos.x, pos.y, pos.z
|
|
end
|
|
|
|
return 0,0,0
|
|
end
|
|
|
|
PART.Inputs.owner_position_x = function(self)
|
|
local owner = get_owner(self)
|
|
|
|
if owner:IsValid() then
|
|
local pos = owner:GetPos()
|
|
|
|
return pos.x
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.owner_position_y = function(self)
|
|
local owner = get_owner(self)
|
|
|
|
if owner:IsValid() then
|
|
local pos = owner:GetPos()
|
|
|
|
return pos.y
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.owner_position_z = function(self)
|
|
local owner = get_owner(self)
|
|
|
|
if owner:IsValid() then
|
|
local pos = owner:GetPos()
|
|
|
|
return pos.z
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.owner_fov = function(self)
|
|
local owner = get_owner(self)
|
|
|
|
if owner:IsValid() and owner.GetFOV then
|
|
return owner:GetFOV()
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.visible = function(self, radius)
|
|
local part = self:GetPhysicalTarget()
|
|
if not part.GetWorldPosition then return 0 end
|
|
part.proxy_pixvis = part.proxy_pixvis or util.GetPixelVisibleHandle()
|
|
return util.PixelVisible(part:GetWorldPosition(), radius or 16, part.proxy_pixvis) or 0
|
|
end
|
|
|
|
PART.Inputs.time = RealTime
|
|
PART.Inputs.synced_time = CurTime
|
|
PART.Inputs.systime = SysTime
|
|
PART.Inputs.stime = SysTime
|
|
PART.Inputs.frametime = FrameTime
|
|
PART.Inputs.ftime = FrameTime
|
|
PART.Inputs.framenumber = FrameNumber
|
|
PART.Inputs.fnumber = FrameNumber
|
|
|
|
PART.Inputs.random = function(self, min, max)
|
|
min = min or 0
|
|
max = max or 1
|
|
return min + math.random()*(max-min)
|
|
end
|
|
|
|
PART.Inputs.random_once = function(self, seed, min, max)
|
|
min = min or 0
|
|
max = max or 1
|
|
|
|
seed = seed or 0
|
|
self.rand_id = self.rand_id or {}
|
|
if seed then
|
|
self.rand_id[seed] = self.rand_id[seed] or min + math.random()*(max-min)
|
|
else
|
|
self.rand = self.rand or min + math.random()*(max-min)
|
|
end
|
|
|
|
return self.rand_id[seed] or self.rand
|
|
end
|
|
|
|
PART.Inputs.lerp = function(self, m, a, b)
|
|
m = tonumber(m) or 0
|
|
a = tonumber(a) or -1
|
|
b = tonumber(b) or 1
|
|
|
|
return (b - a) * m + a
|
|
end
|
|
|
|
for ease,f in pairs(math.ease) do
|
|
if string.find(ease,"In") or string.find(ease,"Out") then
|
|
local f2 = function(self, frac, min, max)
|
|
min = min or 0
|
|
max = max or 1
|
|
return min + f(frac)*(max-min)
|
|
end
|
|
PART.Inputs["ease"..ease] = f2
|
|
PART.Inputs["ease_"..ease] = f2
|
|
PART.Inputs[ease] = f2
|
|
end
|
|
end
|
|
|
|
PART.Inputs.timeex = function(s)
|
|
s.time = s.time or pac.RealTime
|
|
|
|
return pac.RealTime - s.time
|
|
end
|
|
|
|
PART.Inputs.part_distance = function(self, uid1, uid2)
|
|
if not uid1 or not uid2 then return 0 end
|
|
|
|
local PartA = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid1)
|
|
if not PartA:IsValid() then PartA = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid1, self) end
|
|
|
|
local PartB = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid2)
|
|
if not PartB:IsValid() then PartB = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid2, self) end
|
|
|
|
if not PartA:IsValid() or not PartB:IsValid() then return 0 end
|
|
return (PartB:GetWorldPosition() - PartA:GetWorldPosition()):Length()
|
|
end
|
|
|
|
PART.Inputs.event_alternative = function(self, uid1, num1, num2)
|
|
if not uid1 then return 0 end
|
|
|
|
local PartA = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid1)
|
|
if not PartA:IsValid() then PartA = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid1, self) end
|
|
|
|
if PartA.ClassName == "event" then
|
|
if PartA.event_triggered then return num1 or 0
|
|
else return num2 or 0 end
|
|
else return -1 end
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.number_operator_alternative = function(self, comp1, op, comp2, num1, num2)
|
|
if not (comp1 and op and comp2 and num1 and num2) then return -1 end
|
|
if not (isnumber(comp1) and isnumber(comp2) and isnumber(num1) and isnumber(num2)) then return -1 end
|
|
local b = true
|
|
if op == "=" or op == "==" or op == "equal" then
|
|
b = comp1 == comp2
|
|
elseif op == ">" or op == "above" or op == "greater" or op == "greater than" then
|
|
b = comp1 > comp2
|
|
elseif op == ">=" or op == "above or equal" or op == "greater or equal" or op == "greater than or equal" then
|
|
b = comp1 >= comp2
|
|
elseif op == "<" or op == "below" or op == "less" or op == "less than" then
|
|
b = comp1 < comp2
|
|
elseif op == "<=" or op == "below or equal" or op == "less or equal" or op == "less than or equal" then
|
|
b = comp1 <= comp2
|
|
elseif op == "~=" or op == "~=" or op == "not equal" then
|
|
b = comp1 ~= comp2
|
|
end
|
|
if b then return num1 or 0 else return num2 or 0 end
|
|
end
|
|
|
|
do
|
|
local function get_pos(self)
|
|
local part = self:GetPhysicalTarget()
|
|
if not part:IsValid() then return end
|
|
|
|
local pos
|
|
if part.GetWorldPosition then
|
|
pos = part:GetWorldPosition()
|
|
else
|
|
local owner = get_owner(part)
|
|
if not owner:IsValid() then return end
|
|
pos = owner:GetPos()
|
|
end
|
|
|
|
return pos
|
|
end
|
|
|
|
PART.Inputs.eye_position_distance = function(self)
|
|
local pos = get_pos(self)
|
|
if not pos then return 0 end
|
|
|
|
return pos:Distance(pac.EyePos)
|
|
end
|
|
|
|
PART.Inputs.eye_angle_distance = function(self)
|
|
local pos = get_pos(self)
|
|
if not pos then return 0 end
|
|
|
|
return math.Clamp(math.abs(pac.EyeAng:Forward():DotProduct((pos - pac.EyePos):GetNormalized())) - 0.5, 0, 1)
|
|
end
|
|
|
|
end
|
|
|
|
PART.Inputs.aim_length = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local res = util.QuickTrace(owner:EyePos(), self:CalcEyeAngles(owner):Forward() * 16000, {owner, owner:GetParent()})
|
|
|
|
return res.StartPos:Distance(res.HitPos)
|
|
end
|
|
|
|
PART.Inputs.aim_length_fraction = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local res = util.QuickTrace(owner:EyePos(), self:CalcEyeAngles(owner):Forward() * 16000, {owner, owner:GetParent()})
|
|
|
|
return res.Fraction
|
|
end
|
|
|
|
do
|
|
local function get_eye_angle(self, field)
|
|
local owner = get_owner(self)
|
|
|
|
if not owner:IsValid() then return 0 end
|
|
local n = self:CalcEyeAngles(owner)[field]
|
|
|
|
if field == "p" then
|
|
return -(1 + math.NormalizeAngle(n) / 89) / 2 + 1
|
|
end
|
|
|
|
return math.NormalizeAngle(n)/90
|
|
end
|
|
|
|
PART.Inputs.owner_eye_angle_pitch = function(self) return get_eye_angle(self, "p") end
|
|
PART.Inputs.owner_eye_angle_yaw = function(self) return get_eye_angle(self, "y") end
|
|
PART.Inputs.owner_eye_angle_roll = function(self) return get_eye_angle(self, "r") end
|
|
end
|
|
|
|
do
|
|
local function get_scale(self, field)
|
|
local owner = get_owner(self)
|
|
|
|
if not owner:IsValid() then return 1 end
|
|
|
|
return owner.pac_model_scale and owner.pac_model_scale[field] or (owner.GetModelScale and owner:GetModelScale()) or 1
|
|
end
|
|
PART.Inputs.owner_scale_x = function(self) return get_scale(self, "x") end
|
|
PART.Inputs.owner_scale_y = function(self) return get_scale(self, "y") end
|
|
PART.Inputs.owner_scale_z = function(self) return get_scale(self, "z") end
|
|
end
|
|
|
|
-- outfit owner
|
|
PART.Inputs.owner_velocity_length = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return self:GetVelocity(owner):Length()
|
|
end
|
|
|
|
do
|
|
local function get_velocity(self, field)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local dir = self:CalcEyeAngles(owner)
|
|
return dir[field](dir):Dot(self:GetVelocity(owner))
|
|
end
|
|
|
|
PART.Inputs.owner_velocity_forward = function(self) return get_velocity(self, "Forward") end
|
|
PART.Inputs.owner_velocity_right = function(self) return get_velocity(self, "Right") end
|
|
PART.Inputs.owner_velocity_up = function(self) return get_velocity(self, "Up") end
|
|
end
|
|
|
|
do -- velocity world
|
|
local function get_velocity(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return self:GetVelocity(owner)
|
|
end
|
|
|
|
PART.Inputs.owner_velocity_world_forward = function(self) return get_velocity(self)[1] end
|
|
PART.Inputs.owner_velocity_world_right = function(self) return get_velocity(self)[2] end
|
|
PART.Inputs.owner_velocity_world_up = function(self) return get_velocity(self)[3] end
|
|
end
|
|
|
|
-- outfit owner vel increase
|
|
PART.Inputs.owner_velocity_length_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:GetVelocity(owner):Length()
|
|
self.ov_length_i = (self.ov_length_i or 0) + vel * FrameTime()
|
|
return self.ov_length_i
|
|
end
|
|
|
|
do
|
|
PART.Inputs.owner_velocity_forward_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:CalcEyeAngles(owner):Forward():Dot(self:GetVelocity(owner))
|
|
self.ov_forward_i = (self.ov_forward_i or 0) + vel * FrameTime()
|
|
return self.ov_forward_i
|
|
end
|
|
PART.Inputs.owner_velocity_right_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:CalcEyeAngles(owner):Right():Dot(self:GetVelocity(owner))
|
|
self.ov_right_i = (self.ov_right_i or 0) + vel * FrameTime()
|
|
return self.ov_right_i
|
|
end
|
|
PART.Inputs.owner_velocity_up_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:CalcEyeAngles(owner):Up():Dot(self:GetVelocity(owner))
|
|
self.ov_up_i = (self.ov_up_i or 0) + vel * FrameTime()
|
|
return self.ov_up_i
|
|
end
|
|
end
|
|
|
|
do --
|
|
PART.Inputs.owner_velocity_world_forward_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:GetVelocity(owner)[1]
|
|
self.ov_wforward_i = (self.ov_wforward_i or 0) + vel * FrameTime()
|
|
return self.ov_wforward_i
|
|
end
|
|
PART.Inputs.owner_velocity_world_right_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:GetVelocity(owner)[2]
|
|
self.ov_wright_i = (self.ov_wright_i or 0) + vel * FrameTime()
|
|
return self.ov_wright_i
|
|
end
|
|
PART.Inputs.owner_velocity_world_up_increase = function(self)
|
|
local owner = get_owner(self)
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
local vel = self:GetVelocity(owner)[3]
|
|
self.ov_wup_i = (self.ov_wup_i or 0) + vel * FrameTime()
|
|
return self.ov_wup_i
|
|
end
|
|
end
|
|
|
|
do -- velocity
|
|
PART.Inputs.parent_velocity_length = function(self)
|
|
return self:GetVelocity(self:GetPhysicalTarget()):Length()
|
|
end
|
|
|
|
local function get_velocity(self)
|
|
local part = self:GetPhysicalTarget()
|
|
local ang
|
|
|
|
if part.GetWorldAngles then
|
|
ang = part:GetWorldAngles()
|
|
elseif part.GetAngles then
|
|
ang = part:GetAngles()
|
|
end
|
|
|
|
return ang and self:GetVelocity(part), ang
|
|
end
|
|
|
|
PART.Inputs.parent_velocity_forward = function(self)
|
|
local vel, ang = get_velocity(self)
|
|
if not vel then return 0 end
|
|
|
|
return -ang:Forward():Dot(vel)
|
|
end
|
|
PART.Inputs.parent_velocity_right = function(self)
|
|
local vel, ang = get_velocity(self)
|
|
if not vel then return 0 end
|
|
|
|
return ang:Right():Dot(vel)
|
|
end
|
|
PART.Inputs.parent_velocity_up = function(self)
|
|
local vel, ang = get_velocity(self)
|
|
if not vel then return 0 end
|
|
|
|
return ang:Up():Dot(vel)
|
|
end
|
|
end
|
|
|
|
do -- scale
|
|
local function get_scale(self, field)
|
|
local part = self:GetPhysicalTarget()
|
|
if not part:IsValid() then return 1 end
|
|
|
|
return part.Scale and part.Scale[field]*part.Size or 1
|
|
end
|
|
PART.Inputs.parent_scale_x = function(self) return get_scale(self, "x") end
|
|
PART.Inputs.parent_scale_y = function(self) return get_scale(self, "y") end
|
|
PART.Inputs.parent_scale_z = function(self) return get_scale(self, "z") end
|
|
end
|
|
|
|
PART.Inputs.pose_parameter = function(self, name)
|
|
if not name then return 0 end
|
|
local owner = get_owner(self)
|
|
if owner:IsValid() and owner.GetPoseParameter then return owner:GetPoseParameter(name) end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.pose_parameter_true = function(self, name)
|
|
if not name then return 0 end
|
|
local owner = get_owner(self)
|
|
if owner:IsValid() then
|
|
local min, max = owner:GetPoseParameterRange(owner:LookupPoseParameter(name))
|
|
return min + (max - min)*(owner:GetPoseParameter(name))
|
|
end
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.command = function(self, name)
|
|
local ply = self:GetPlayerOwner()
|
|
if ply.pac_proxy_events then
|
|
local data
|
|
if not name then data = ply.pac_proxy_events[self.Name]
|
|
else data = ply.pac_proxy_events[name] end
|
|
|
|
if data then
|
|
data.x = data.x or 0
|
|
data.y = data.y or 0
|
|
data.z = data.z or 0
|
|
return data.x, data.y, data.z
|
|
end
|
|
end
|
|
|
|
return 0, 0, 0
|
|
end
|
|
|
|
PART.Inputs.voice_volume = function(self)
|
|
local ply = self:GetPlayerOwner()
|
|
if not IsValid(ply) then return 0 end
|
|
return ply:VoiceVolume()
|
|
end
|
|
|
|
PART.Inputs.voice_volume_scale = function(self)
|
|
local ply = self:GetPlayerOwner()
|
|
return ply:GetVoiceVolumeScale()
|
|
end
|
|
|
|
do -- light amount
|
|
local ColorToHSV = ColorToHSV
|
|
local render = render
|
|
local function get_color(self, field)
|
|
local part = self:GetPhysicalTarget()
|
|
if not part:IsValid() then return 0 end
|
|
if not part.GetWorldPosition then return 0 end
|
|
local v = field and render.GetLightColor(part:GetWorldPosition()):ToColor()[field] or render.GetLightColor(part:GetWorldPosition()):ToColor()
|
|
|
|
if part.ProperColorRange then
|
|
if field then return v / 255 else return v['r']/255, v['g']/255, v['b']/255 end
|
|
end
|
|
|
|
if field then return v else return v['r'], v['g'], v['b'] end
|
|
end
|
|
|
|
PART.Inputs.light_amount = function(self) return get_color(self) end
|
|
PART.Inputs.light_amount_r = function(self) return get_color(self, "r") end
|
|
PART.Inputs.light_amount_g = function(self) return get_color(self, "g") end
|
|
PART.Inputs.light_amount_b = function(self) return get_color(self, "b") end
|
|
|
|
PART.Inputs.light_value = function(self)
|
|
local part = self:GetPhysicalTarget()
|
|
if not part:IsValid() then return 0 end
|
|
if not part.GetWorldPosition then return 0 end
|
|
|
|
local h, s, v = ColorToHSV(render.GetLightColor(part:GetWorldPosition()):ToColor())
|
|
return v
|
|
end
|
|
end
|
|
|
|
do -- ambient light
|
|
local render = render
|
|
local function get_color(self, field)
|
|
local part = self:GetTarget()
|
|
if not part:IsValid() then return 0 end
|
|
|
|
local v = field and render.GetAmbientLightColor():ToColor()[field] or render.GetAmbientLightColor():ToColor()
|
|
|
|
if part.ProperColorRange then
|
|
if field then return v / 255 else return v['r']/255, v['g']/255, v['b']/255 end
|
|
end
|
|
|
|
if field then return v else return v['r'], v['g'], v['b'] end
|
|
end
|
|
|
|
PART.Inputs.ambient_light = function(self) return get_color(self) end
|
|
PART.Inputs.ambient_light_r = function(self) return get_color(self, "r") end
|
|
PART.Inputs.ambient_light_g = function(self) return get_color(self, "g") end
|
|
PART.Inputs.ambient_light_b = function(self) return get_color(self, "b") end
|
|
end
|
|
|
|
do -- health and armor
|
|
PART.Inputs.owner_health = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:Health()
|
|
end
|
|
PART.Inputs.owner_max_health = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:GetMaxHealth()
|
|
end
|
|
PART.Inputs.owner_health_fraction = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:Health() / owner:GetMaxHealth()
|
|
end
|
|
|
|
PART.Inputs.owner_armor = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:Armor()
|
|
end
|
|
PART.Inputs.owner_max_armor = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:GetMaxArmor()
|
|
end
|
|
PART.Inputs.owner_armor_fraction = function(self)
|
|
local owner = self:GetPlayerOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner:Armor() / owner:GetMaxArmor()
|
|
end
|
|
end
|
|
|
|
do -- weapon and player color
|
|
local Color = Color
|
|
local function get_color(self, get, field)
|
|
local color = field and get(self)[field] or get(self)
|
|
local part = self:GetTarget()
|
|
|
|
if part.ProperColorRange then
|
|
if field then return color else return color[1], color[2], color[3] end
|
|
end
|
|
|
|
if field then return color*255 else return color[1]*255, color[2]*255, color[3]*255 end
|
|
end
|
|
|
|
do
|
|
local function get_player_color(self)
|
|
local owner = self:GetPlayerOwner()
|
|
|
|
if not owner:IsValid() then return Vector(1,1,1) end
|
|
|
|
return owner:GetPlayerColor()
|
|
end
|
|
|
|
PART.Inputs.player_color = function(self) return get_color(self, get_player_color) end
|
|
PART.Inputs.player_color_r = function(self) return get_color(self, get_player_color, "r") end
|
|
PART.Inputs.player_color_g = function(self) return get_color(self, get_player_color, "g") end
|
|
PART.Inputs.player_color_b = function(self) return get_color(self, get_player_color, "b") end
|
|
end
|
|
|
|
do
|
|
local function get_weapon_color(self)
|
|
local owner = self:GetPlayerOwner()
|
|
|
|
if not owner:IsValid() then return Vector(1,1,1) end
|
|
|
|
return owner:GetWeaponColor()
|
|
end
|
|
|
|
PART.Inputs.weapon_color = function(self) return get_color(self, get_weapon_color) end
|
|
PART.Inputs.weapon_color_r = function(self) return get_color(self, get_weapon_color, "r") end
|
|
PART.Inputs.weapon_color_g = function(self) return get_color(self, get_weapon_color, "g") end
|
|
PART.Inputs.weapon_color_b = function(self) return get_color(self, get_weapon_color, "b") end
|
|
end
|
|
end
|
|
|
|
do -- ammo
|
|
local function get_weapon(self)
|
|
local owner = self:GetRootPart():GetOwner()
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
if owner.GetActiveWeapon and not owner:IsWeapon() then
|
|
owner = self:GetPlayerOwner()
|
|
end
|
|
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return owner.GetActiveWeapon and owner:GetActiveWeapon() or owner, owner
|
|
end
|
|
|
|
PART.Inputs.owner_total_ammo = function(self, id)
|
|
local owner = self:GetPlayerOwner()
|
|
id = id and id:lower()
|
|
|
|
if not owner:IsValid() then return 0 end
|
|
|
|
return (owner.GetAmmoCount and id) and owner:GetAmmoCount(id) or 0
|
|
end
|
|
|
|
PART.Inputs.weapon_primary_ammo = function(self)
|
|
local wep = get_weapon(self)
|
|
|
|
return wep:IsValid() and wep.Clip1 and wep:Clip1() or 0
|
|
end
|
|
PART.Inputs.weapon_primary_total_ammo = function(self)
|
|
local wep, owner = get_weapon(self)
|
|
|
|
return wep:IsValid() and (wep.GetPrimaryAmmoType and owner.GetAmmoCount) and owner:GetAmmoCount(wep:GetPrimaryAmmoType()) or 0
|
|
end
|
|
PART.Inputs.weapon_primary_clipsize = function(self)
|
|
local wep = get_weapon(self)
|
|
|
|
return wep:IsValid() and wep.GetMaxClip1 and wep:GetMaxClip1() or 0
|
|
end
|
|
PART.Inputs.weapon_secondary_ammo = function(self)
|
|
local wep = get_weapon(self)
|
|
|
|
return wep:IsValid() and wep.Clip2 and wep:Clip2() or 0
|
|
end
|
|
PART.Inputs.weapon_secondary_total_ammo = function(self)
|
|
local wep, owner = get_weapon(self)
|
|
|
|
return wep:IsValid() and (wep.GetSecondaryAmmoType and owner.GetAmmoCount) and owner:GetAmmoCount(wep:GetSecondaryAmmoType()) or 0
|
|
end
|
|
PART.Inputs.weapon_secondary_clipsize = function(self)
|
|
local wep = get_weapon(self)
|
|
|
|
return wep:IsValid() and wep.GetMaxClip2 and wep:GetMaxClip2() or 0
|
|
end
|
|
end
|
|
|
|
PART.Inputs.hsv_to_color = function(self, h, s, v)
|
|
|
|
local part = self:GetTarget()
|
|
if not part:IsValid() then return end
|
|
|
|
h = tonumber(h) or 0
|
|
s = tonumber(s) or 1
|
|
v = tonumber(v) or 1
|
|
|
|
local c = HSVToColor(h%360, s, v)
|
|
|
|
if part.ProperColorRange then
|
|
return c.r/255, c.g/255, c.b/255
|
|
end
|
|
|
|
return c.r, c.g, c.b
|
|
end
|
|
|
|
do
|
|
PART.Inputs.feedback = function(self)
|
|
if not self.feedback then return 0 end
|
|
return self.feedback[1] or 0
|
|
end
|
|
|
|
PART.Inputs.feedback_x = function(self)
|
|
if not self.feedback then return 0 end
|
|
return self.feedback[1] or 0
|
|
end
|
|
|
|
PART.Inputs.feedback_y = function(self)
|
|
if not self.feedback then return 0 end
|
|
return self.feedback[2] or 0
|
|
end
|
|
|
|
PART.Inputs.feedback_z = function(self)
|
|
if not self.feedback then return 0 end
|
|
return self.feedback[3] or 0
|
|
end
|
|
end
|
|
|
|
PART.Inputs.flat_dot_forward = function(self)
|
|
local part = get_owner(self)
|
|
|
|
if part:IsValid() then
|
|
local ang = part:IsPlayer() and part:EyeAngles() or part:GetAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
local dir = pac.EyePos - part:EyePos()
|
|
dir[3] = 0
|
|
dir:Normalize()
|
|
return dir:Dot(ang:Forward())
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
PART.Inputs.flat_dot_right = function(self)
|
|
local part = get_owner(self)
|
|
|
|
if part:IsValid() then
|
|
local ang = part:IsPlayer() and part:EyeAngles() or part:GetAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
local dir = pac.EyePos - part:EyePos()
|
|
dir[3] = 0
|
|
dir:Normalize()
|
|
return dir:Dot(ang:Right())
|
|
end
|
|
|
|
return 0
|
|
end
|
|
|
|
net.Receive("pac_proxy", function()
|
|
local ply = net.ReadEntity()
|
|
local str = net.ReadString()
|
|
|
|
local x = net.ReadFloat()
|
|
local y = net.ReadFloat()
|
|
local z = net.ReadFloat()
|
|
|
|
if ply:IsValid() then
|
|
ply.pac_proxy_events = ply.pac_proxy_events or {}
|
|
ply.pac_proxy_events[str] = {name = str, x = x, y = y, z = z}
|
|
end
|
|
end)
|
|
|
|
function PART:CheckLastVar(part)
|
|
if self.last_var ~= self.VariableName then
|
|
if self.last_var then
|
|
part:SetProperty(self.VariableName, self.last_var_val)
|
|
end
|
|
self.last_var = self.VariableName
|
|
self.last_var_val = part:GetProperty(self.VariableName)
|
|
end
|
|
end
|
|
|
|
local allowed = {
|
|
number = true,
|
|
Vector = true,
|
|
Angle = true,
|
|
boolean = true,
|
|
}
|
|
|
|
function PART:SetExpression(str)
|
|
self.Expression = str
|
|
self.ExpressionFunc = nil
|
|
|
|
if str and str ~= "" then
|
|
local lib = {}
|
|
|
|
for name, func in pairs(PART.Inputs) do
|
|
lib[name] = function(...) return func(self, ...) end
|
|
end
|
|
|
|
local ok, res = pac.CompileExpression(str, lib)
|
|
if ok then
|
|
self.ExpressionFunc = res
|
|
self.ExpressionError = nil
|
|
self:SetError()
|
|
else
|
|
self.ExpressionFunc = true
|
|
self.ExpressionError = res
|
|
self:SetError(res)
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:OnHide()
|
|
self.time = nil
|
|
self.rand = nil
|
|
self.rand_id = nil
|
|
self.vec_additive = Vector()
|
|
|
|
if self.ResetVelocitiesOnHide then
|
|
self.last_vel = nil
|
|
self.last_pos = nil
|
|
self.last_vel_smooth = nil
|
|
end
|
|
|
|
if self.VariableName == "Hide" then
|
|
-- cleanup event triggers on hide
|
|
local part = self:GetTarget()
|
|
if self.AffectChildren then
|
|
for _, part in ipairs(self:GetChildren()) do
|
|
part:SetEventTrigger(self, false)
|
|
part.proxy_hide = nil
|
|
end
|
|
elseif part:IsValid() then
|
|
part:SetEventTrigger(self, false)
|
|
part.proxy_hide = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:OnShow()
|
|
self.time = nil
|
|
self.rand = nil
|
|
self.rand_id = nil
|
|
self.vec_additive = Vector()
|
|
end
|
|
|
|
local function set(self, part, x, y, z, children)
|
|
local val = part:GetProperty(self.VariableName)
|
|
local T = type(val)
|
|
|
|
if allowed[T] then
|
|
if T == "boolean" then
|
|
x = x or val == true and 1 or 0
|
|
local b = tonumber(x) > 0
|
|
|
|
|
|
-- special case for hide to make it behave like events
|
|
if self.VariableName == "Hide" then
|
|
|
|
if part.proxy_hide ~= b then
|
|
|
|
-- in case parts start as hidden
|
|
if b == false then
|
|
part:SetKeyValueRecursive("Hide", b)
|
|
end
|
|
|
|
-- we want any nested proxies to think twice before they decide to enable themselves
|
|
part:CallRecursiveOnClassName("proxy", "OnThink")
|
|
|
|
part:SetEventTrigger(self, b)
|
|
|
|
part.proxy_hide = b
|
|
end
|
|
|
|
-- don't apply anything to children
|
|
return
|
|
else
|
|
part:SetProperty(self.VariableName, b)
|
|
end
|
|
elseif T == "number" then
|
|
x = x or val
|
|
part:SetProperty(self.VariableName, tonumber(x) or 0)
|
|
else
|
|
if self.Axis ~= "" and val[self.Axis] then
|
|
val = val * 1
|
|
val[self.Axis] = x
|
|
else
|
|
if T == "Angle" then
|
|
val = val * 1
|
|
val.p = x or val.p
|
|
val.y = y or val.y
|
|
val.r = z or val.r
|
|
elseif T == "Vector" then
|
|
val = val * 1
|
|
val.x = x or val.x
|
|
val.y = y or val.y
|
|
val.z = z or val.z
|
|
end
|
|
end
|
|
|
|
part:SetProperty(self.VariableName, val)
|
|
end
|
|
end
|
|
|
|
if children then
|
|
for _, part in ipairs(part:GetChildren()) do
|
|
set(self, part, x, y, z, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:RunExpression(ExpressionFunc)
|
|
if ExpressionFunc==true then
|
|
return false,self.ExpressionError
|
|
end
|
|
return pcall(ExpressionFunc)
|
|
end
|
|
|
|
function PART:OnThink()
|
|
local part = self:GetTarget()
|
|
if not part:IsValid() then return end
|
|
if part.ClassName == 'woohoo' then return end
|
|
|
|
self:CalcVelocity()
|
|
|
|
local ExpressionFunc = self.ExpressionFunc
|
|
|
|
if not ExpressionFunc then
|
|
self:SetExpression(self.Expression)
|
|
ExpressionFunc = self.ExpressionFunc
|
|
end
|
|
|
|
if ExpressionFunc then
|
|
|
|
local ok, x,y,z = self:RunExpression(ExpressionFunc)
|
|
|
|
if not ok then
|
|
if self:GetPlayerOwner() == pac.LocalPlayer and self.Expression ~= self.LastBadExpression then
|
|
chat.AddText(Color(255,180,180),"============\n[ERR] PAC Proxy error on "..tostring(self)..":\n"..x.."\n============\n")
|
|
self.LastBadExpression = self.Expression
|
|
end
|
|
return
|
|
end
|
|
|
|
if x and not isnumber(x) then x = 0 end
|
|
if y and not isnumber(y) then y = 0 end
|
|
if z and not isnumber(z) then z = 0 end
|
|
|
|
|
|
if self.Additive then
|
|
if x then
|
|
self.vec_additive[1] = (self.vec_additive[1] or 0) + x
|
|
x = self.vec_additive[1]
|
|
end
|
|
|
|
if y then
|
|
self.vec_additive[2] = (self.vec_additive[2] or 0) + y
|
|
y = self.vec_additive[2]
|
|
end
|
|
|
|
if z then
|
|
self.vec_additive[3] = (self.vec_additive[3] or 0) + z
|
|
z = self.vec_additive[3]
|
|
end
|
|
end
|
|
|
|
self.feedback = self.feedback or {}
|
|
self.feedback[1] = x
|
|
self.feedback[2] = y
|
|
self.feedback[3] = z
|
|
|
|
if self.AffectChildren then
|
|
for _, part in ipairs(self:GetChildren()) do
|
|
set(self, part, x, y, z, true)
|
|
end
|
|
else
|
|
set(self, part, x, y, z)
|
|
end
|
|
|
|
if pace and pace.IsActive() then
|
|
|
|
local str = ""
|
|
|
|
if x then str = str .. math.Round(x, 3) end
|
|
if y then str = str .. ", " .. math.Round(y, 3) end
|
|
if z then str = str .. ", " .. math.Round(z, 3) end
|
|
|
|
local val = part:GetProperty(self.VariableName)
|
|
local T = type(val)
|
|
|
|
if T == "boolean" then
|
|
str = tonumber(x) > 0 and "true" or "false"
|
|
elseif T == "Vector" then
|
|
str = "Vector(" .. str .. ")"
|
|
elseif T == "Angle" then
|
|
str = "Angle(" .. str .. ")"
|
|
end
|
|
|
|
self.debug_var = str
|
|
|
|
if self.Name == "" and pace.current_part == self and self.pace_properties and IsValid(self.pace_properties["Name"]) then
|
|
self.pace_properties["Name"]:SetText(self:GetNiceName())
|
|
end
|
|
end
|
|
else
|
|
|
|
local post_function = self.Functions[self.Function]
|
|
local input_function = self.Inputs[self.Input]
|
|
|
|
if post_function and input_function then
|
|
local ran, err = pcall( input_function, self )
|
|
|
|
if not ran then
|
|
error("proxy function " .. tostring( self.Input ) .. " | " .. tostring( self.Function ) .. " | " .. tostring( self ) .. " failed: " .. err)
|
|
end
|
|
|
|
local input_number = err
|
|
|
|
if not isnumber(input_number) then
|
|
error("proxy function " .. self.Input .. " does not return a number!")
|
|
end
|
|
|
|
local num = self.Min + (self.Max - self.Min) * ((post_function(((input_number / self.InputDivider) + self.Offset) * self.InputMultiplier, self) + 1) / 2) ^ self.Pow
|
|
|
|
if self.Additive then
|
|
self.vec_additive[1] = (self.vec_additive[1] or 0) + num
|
|
num = self.vec_additive[1]
|
|
end
|
|
|
|
if self.AffectChildren then
|
|
for _, part in ipairs(self:GetChildren()) do
|
|
set(self, part, num, nil, nil, true)
|
|
end
|
|
else
|
|
set(self, part, num)
|
|
end
|
|
|
|
if pace and pace.IsActive() then
|
|
self.debug_var = math.Round(num, 3)
|
|
end
|
|
|
|
if self.Name == "" and pace.current_part == self and self.pace_properties and IsValid(self.pace_properties["Name"]) then
|
|
self.pace_properties["Name"]:SetText(self:GetNiceName())
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
BUILDER:Register()
|