mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
385
lua/pac3/core/client/parts/animation.lua
Normal file
385
lua/pac3/core/client/parts/animation.lua
Normal file
@@ -0,0 +1,385 @@
|
||||
--[[
|
||||
| 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 FrameTime = FrameTime
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
local AnimStack
|
||||
AnimStack = {
|
||||
__index = {
|
||||
push = function(self, part)
|
||||
local stack = self.stack
|
||||
|
||||
if #stack == 0 then
|
||||
-- Empty stack
|
||||
table.insert(stack, part)
|
||||
else
|
||||
-- Stop the current animation if it's not self
|
||||
local top = self:getTop()
|
||||
if top ~= part then
|
||||
if top then top:OnStackStop() end
|
||||
|
||||
-- Remove self from stack to move to end and also prevent things from breaking because table.RemoveByValue() only removes the first instance
|
||||
table.RemoveByValue(stack, part)
|
||||
table.insert(stack, part)
|
||||
end
|
||||
end
|
||||
|
||||
part:OnStackStart()
|
||||
end,
|
||||
pop = function(self, part)
|
||||
part:OnStackStop()
|
||||
local stack = self.stack
|
||||
|
||||
-- Remove self from animation stack
|
||||
if table.RemoveByValue(stack, part) == #stack + 1 then
|
||||
-- This was the current animation so play the next in the stack
|
||||
local top = self:getTop()
|
||||
if top then top:OnStackStart() end
|
||||
end
|
||||
end,
|
||||
getTop = function(self)
|
||||
local stack = self.stack
|
||||
local top = stack[#stack]
|
||||
-- Remove invalid parts
|
||||
while top and not top:IsValid() do
|
||||
table.remove(stack)
|
||||
top = stack[#stack]
|
||||
end
|
||||
return top
|
||||
end
|
||||
},
|
||||
__call = function(meta)
|
||||
return setmetatable({
|
||||
stack = {}
|
||||
}, meta)
|
||||
end,
|
||||
get = function(ent)
|
||||
local animStack = ent.pac_animation_stack
|
||||
if not animStack then
|
||||
animStack = AnimStack()
|
||||
ent.pac_animation_stack = animStack
|
||||
end
|
||||
return animStack
|
||||
end
|
||||
}
|
||||
setmetatable(AnimStack, AnimStack)
|
||||
|
||||
PART.ClassName = "animation"
|
||||
PART.ThinkTime = 0
|
||||
PART.Groups = {'entity', 'model', 'modifiers'}
|
||||
PART.Icon = 'icon16/eye.png'
|
||||
|
||||
PART.frame = 0
|
||||
|
||||
BUILDER
|
||||
:StartStorableVars()
|
||||
:GetSet("Loop", true)
|
||||
:GetSet("PingPongLoop", false)
|
||||
:GetSet("SequenceName", "", {enums = function(part) local tbl = {} for k,v in pairs(part:GetSequenceList()) do tbl[v] = v end return tbl end})
|
||||
:GetSet("Rate", 1, {editor_sensitivity = 0.1})
|
||||
:GetSet("Offset", 0)
|
||||
:GetSet("Min", 0)
|
||||
:GetSet("Max", 1)
|
||||
:GetSet("WeaponHoldType", "none", {enums = function(part) return part.ValidHoldTypes end})
|
||||
:GetSet("OwnerCycle", false)
|
||||
:GetSet("InvertFrames", false)
|
||||
:GetSet("ResetOnHide", true)
|
||||
:EndStorableVars()
|
||||
|
||||
local tonumber = tonumber
|
||||
|
||||
PART.ValidHoldTypes =
|
||||
{
|
||||
pistol = ACT_HL2MP_IDLE_PISTOL,
|
||||
smg = ACT_HL2MP_IDLE_SMG1,
|
||||
grenade = ACT_HL2MP_IDLE_GRENADE,
|
||||
ar2 = ACT_HL2MP_IDLE_AR2,
|
||||
shotgun = ACT_HL2MP_IDLE_SHOTGUN,
|
||||
rpg = ACT_HL2MP_IDLE_RPG,
|
||||
physgun = ACT_HL2MP_IDLE_PHYSGUN,
|
||||
crossbow = ACT_HL2MP_IDLE_CROSSBOW,
|
||||
melee = ACT_HL2MP_IDLE_MELEE,
|
||||
slam = ACT_HL2MP_IDLE_SLAM,
|
||||
normal = ACT_HL2MP_IDLE,
|
||||
fist = ACT_HL2MP_IDLE_FIST,
|
||||
melee2 = ACT_HL2MP_IDLE_MELEE2,
|
||||
passive = ACT_HL2MP_IDLE_PASSIVE,
|
||||
knife = ACT_HL2MP_IDLE_KNIFE,
|
||||
duel = ACT_HL2MP_IDLE_DUEL,
|
||||
camera = ACT_HL2MP_IDLE_CAMERA,
|
||||
revolver = ACT_HL2MP_IDLE_REVOLVER,
|
||||
|
||||
zombie = ACT_HL2MP_IDLE_ZOMBIE,
|
||||
magic = ACT_HL2MP_IDLE_MAGIC,
|
||||
meleeangry = ACT_HL2MP_IDLE_MELEE_ANGRY,
|
||||
angry = ACT_HL2MP_IDLE_ANGRY,
|
||||
suitcase = ACT_HL2MP_IDLE_SUITCASE,
|
||||
scared = ACT_HL2MP_IDLE_SCARED,
|
||||
}
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = self:GetSequenceName()
|
||||
|
||||
if str == "" and self:GetWeaponHoldType() ~= "none" then
|
||||
str = self:GetWeaponHoldType()
|
||||
end
|
||||
|
||||
return pac.PrettifyName(str)
|
||||
end
|
||||
|
||||
function PART:GetSequenceList()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
return ent:GetSequenceList()
|
||||
end
|
||||
|
||||
return {"none"}
|
||||
end
|
||||
|
||||
PART.GetSequenceNameList = PART.GetSequenceList
|
||||
|
||||
function PART:OnStackStop()
|
||||
-- Move code from PART:OnHide() to here
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if not self:GetResetOnHide() then
|
||||
self.SequenceCycle = ent:GetCycle()
|
||||
self.storeFrame = self.frame
|
||||
else
|
||||
self.SequenceCycle = nil
|
||||
self.frame = 0
|
||||
end
|
||||
|
||||
if ent.pac_animation_sequences then
|
||||
ent.pac_animation_sequences[self] = nil
|
||||
end
|
||||
|
||||
if ent.pac_animation_holdtypes then
|
||||
ent.pac_animation_holdtypes[self] = nil
|
||||
end
|
||||
|
||||
if not ent:IsPlayer() and self.prevSequence then
|
||||
ent:ResetSequence(self.prevSequence)
|
||||
self.prevSequence = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop animation and remove from animation stack
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
AnimStack.get(ent):pop(self)
|
||||
end
|
||||
|
||||
PART.random_seqname = ""
|
||||
|
||||
function PART:SetSequenceName(name)
|
||||
self.SequenceName = name
|
||||
self.random_seqname = table.Random(name:Split(";"))
|
||||
|
||||
if not self:IsHidden() then
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnStackStart()
|
||||
-- Moved code from PART:OnShow() to here
|
||||
self.PlayingSequenceFrom = RealTime()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
self.prevSequence = ent:GetSequence()
|
||||
self.random_seqname = table.Random(self.SequenceName:Split(";"))
|
||||
|
||||
if self.random_seqname ~= "" then
|
||||
local seq = ent:LookupSequence(self.random_seqname) or 0
|
||||
local count = ent:GetSequenceCount() or 0
|
||||
|
||||
if seq < 0 or seq > count or count < 0 then
|
||||
return
|
||||
end
|
||||
|
||||
ent.pac_animation_sequences = ent.pac_animation_sequences or {}
|
||||
ent.pac_animation_sequences[self] = ent.pac_animation_sequences[self] or {}
|
||||
|
||||
local tbl = ent.pac_animation_sequences[self]
|
||||
|
||||
tbl.part = self
|
||||
|
||||
if seq ~= -1 then
|
||||
tbl.seq = seq
|
||||
else
|
||||
seq = tonumber(self.random_seqname) or -1
|
||||
|
||||
if seq ~= -1 then
|
||||
tbl.seq = seq
|
||||
else
|
||||
ent.pac_animation_sequences[self] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if seq ~= -1 then
|
||||
ent:ResetSequence(seq)
|
||||
ent:SetSequence(seq)
|
||||
if not self:GetResetOnHide() then
|
||||
ent:ResetSequenceInfo()
|
||||
|
||||
for i = 1, 10 do
|
||||
ent:FrameAdvance(1)
|
||||
end
|
||||
|
||||
ent:ResetSequenceInfo()
|
||||
end
|
||||
end
|
||||
|
||||
elseif ent:IsPlayer() then
|
||||
local t = self.WeaponHoldType
|
||||
t = t:lower()
|
||||
|
||||
local index = self.ValidHoldTypes[t]
|
||||
|
||||
ent.pac_animation_holdtypes = ent.pac_animation_holdtypes or {}
|
||||
|
||||
if index == nil then
|
||||
ent.pac_animation_holdtypes[self] = nil
|
||||
else
|
||||
local params = {}
|
||||
params[ACT_MP_STAND_IDLE] = index + 0
|
||||
params[ACT_MP_WALK] = index + 1
|
||||
params[ACT_MP_RUN] = index + 2
|
||||
params[ACT_MP_CROUCH_IDLE] = index + 3
|
||||
params[ACT_MP_CROUCHWALK] = index + 4
|
||||
params[ACT_MP_ATTACK_STAND_PRIMARYFIRE] = index + 5
|
||||
params[ACT_MP_ATTACK_CROUCH_PRIMARYFIRE] = index + 5
|
||||
params[ACT_MP_RELOAD_STAND] = index + 6
|
||||
params[ACT_MP_RELOAD_CROUCH] = index + 7
|
||||
params[ACT_MP_JUMP] = index + 8
|
||||
params[ACT_RANGE_ATTACK1] = index + 9
|
||||
params[ACT_MP_SWIM_IDLE] = index + 10
|
||||
params[ACT_MP_SWIM] = index + 11
|
||||
|
||||
-- "normal" jump animation doesn't exist
|
||||
if t == "normal" then
|
||||
params[ACT_MP_JUMP] = ACT_HL2MP_JUMP_SLAM
|
||||
end
|
||||
|
||||
-- these two aren't defined in ACTs for whatever reason
|
||||
if t == "knife" or t == "melee2" then
|
||||
params[ACT_MP_CROUCH_IDLE] = nil
|
||||
end
|
||||
|
||||
params.part = self
|
||||
|
||||
ent.pac_animation_holdtypes[self] = params
|
||||
end
|
||||
end
|
||||
|
||||
if not self:GetResetOnHide() and self.SequenceCycle then
|
||||
ent:SetCycle(self.SequenceCycle)
|
||||
self.SequenceCycle = nil
|
||||
|
||||
if self.storeFrame then
|
||||
self.frame = self.storeFrame
|
||||
self.storeFrame = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Play animation and move to top of animation stack
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
AnimStack.get(ent):push(self)
|
||||
end
|
||||
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsPlayer() then
|
||||
self:OnUpdateAnimation(nil)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnUpdateAnimation(ply)
|
||||
if self:IsHiddenCached() then return end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() or not ent.pac_animation_stack or ent.pac_animation_stack.stack[#ent.pac_animation_stack.stack] ~= self then return end
|
||||
|
||||
-- from UpdateAnimation hook
|
||||
if ply and ent ~= ply then return end
|
||||
|
||||
if not self.random_seqname then return end
|
||||
|
||||
local seq, duration = ent:LookupSequence(self.random_seqname)
|
||||
|
||||
local count = ent:GetSequenceCount() or 0
|
||||
if seq < 0 or seq >= count then
|
||||
-- It's an invalid sequence. Don't bother
|
||||
return
|
||||
end
|
||||
|
||||
if self.OwnerCycle then
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
|
||||
if IsValid(owner) then
|
||||
ent:SetCycle(owner:GetCycle())
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local min = self.Min
|
||||
local max = self.Max
|
||||
local maxmin = max - min
|
||||
|
||||
if min == max then
|
||||
local cycle = min
|
||||
|
||||
if pac.IsNumberValid(cycle) then
|
||||
ent:SetCycle(self.InvertFrames and (1 - cycle) or cycle)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local rate = (duration == 0) and 0 or (self.Rate / duration / math.abs(maxmin) * FrameTime())
|
||||
|
||||
if self.PingPongLoop then
|
||||
if self.Loop then
|
||||
self.frame = (self.frame + rate) % 2
|
||||
else
|
||||
self.frame = math.max(math.min(self.frame + rate, 2), 0)
|
||||
end
|
||||
local cycle = min + math.abs(1 - (self.frame + 1 + self.Offset) % 2) * maxmin
|
||||
|
||||
if pac.IsNumberValid(cycle) then
|
||||
ent:SetCycle(self.InvertFrames and (1 - cycle) or cycle)
|
||||
end
|
||||
else
|
||||
if self.Loop then
|
||||
self.frame = (self.frame + rate) % 2
|
||||
else
|
||||
self.frame = math.max(math.min(self.frame + rate, 1), 0)
|
||||
end
|
||||
local cycle = min + (self.frame + self.Offset) % 1 * maxmin
|
||||
|
||||
if pac.IsNumberValid(cycle) then
|
||||
ent:SetCycle(self.InvertFrames and (1 - cycle) or cycle)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
240
lua/pac3/core/client/parts/beam.lua
Normal file
240
lua/pac3/core/client/parts/beam.lua
Normal file
@@ -0,0 +1,240 @@
|
||||
--[[
|
||||
| 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 LocalToWorld = LocalToWorld
|
||||
local render_StartBeam = render.StartBeam
|
||||
local render_AddBeam = render.AddBeam
|
||||
local render_EndBeam = render.EndBeam
|
||||
local color_white = color_white
|
||||
local math_sin = math.sin
|
||||
local math_pi = math.pi
|
||||
local Angle = Angle
|
||||
local Lerp = Lerp
|
||||
local Vector = Vector
|
||||
local Color = Color
|
||||
|
||||
-- feel free to use this wherever!
|
||||
do
|
||||
local ax,ay,az = 0,0,0
|
||||
local bx,by,bz = 0,0,0
|
||||
local adx,ady,adz = 0,0,0
|
||||
local bdx,bdy,bdz = 0,0,0
|
||||
|
||||
local frac = 0
|
||||
local wave = 0
|
||||
local bendmult = 0
|
||||
|
||||
local vector = Vector()
|
||||
local color = Color(255, 255, 255, 255)
|
||||
|
||||
function pac.DrawBeam(veca, vecb, dira, dirb, bend, res, width, start_color, end_color, frequency, tex_stretch, tex_scroll, width_bend, width_bend_size, width_start_mul, width_end_mul)
|
||||
|
||||
if not veca or not vecb or not dira or not dirb then return end
|
||||
|
||||
ax = veca.x; ay = veca.y; az = veca.z
|
||||
bx = vecb.x; by = vecb.y; bz = vecb.z
|
||||
|
||||
adx = dira.x; ady = dira.y; adz = dira.z
|
||||
bdx = dirb.x; bdy = dirb.y; bdz = dirb.z
|
||||
|
||||
bend = bend or 10
|
||||
res = math.max(res or 32, 2)
|
||||
width = width or 10
|
||||
start_color = start_color or color_white
|
||||
end_color = end_color or color_white
|
||||
frequency = frequency or 1
|
||||
tex_stretch = tex_stretch or 1
|
||||
width_bend = width_bend or 0
|
||||
width_bend_size = width_bend_size or 1
|
||||
tex_scroll = tex_scroll or 0
|
||||
width_start_mul = width_start_mul or 1
|
||||
width_end_mul = width_end_mul or 1
|
||||
|
||||
render_StartBeam(res + 1)
|
||||
|
||||
for i = 0, res do
|
||||
|
||||
frac = i / res
|
||||
wave = frac * math_pi * frequency
|
||||
bendmult = math_sin(wave) * bend
|
||||
|
||||
vector.x = Lerp(frac, ax, bx) + Lerp(frac, adx * bendmult, bdx * bendmult)
|
||||
vector.y = Lerp(frac, ay, by) + Lerp(frac, ady * bendmult, bdy * bendmult)
|
||||
vector.z = Lerp(frac, az, bz) + Lerp(frac, adz * bendmult, bdz * bendmult)
|
||||
|
||||
color.r = start_color.r == end_color.r and start_color.r or Lerp(frac, start_color.r, end_color.r)
|
||||
color.g = start_color.g == end_color.g and start_color.g or Lerp(frac, start_color.g, end_color.g)
|
||||
color.b = start_color.b == end_color.b and start_color.b or Lerp(frac, start_color.b, end_color.b)
|
||||
color.a = start_color.a == end_color.a and start_color.a or Lerp(frac, start_color.a, end_color.a)
|
||||
|
||||
render_AddBeam(
|
||||
vector,
|
||||
(width + ((math_sin(wave) ^ width_bend_size) * width_bend)) * Lerp(frac, width_start_mul, width_end_mul),
|
||||
(i / tex_stretch) + tex_scroll,
|
||||
color
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
render_EndBeam()
|
||||
end
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "beam"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/vector.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Material", "cable/rope")
|
||||
BUILDER:GetSetPart("EndPoint")
|
||||
BUILDER:GetSet("Bend", 10)
|
||||
BUILDER:GetSet("Frequency", 1)
|
||||
BUILDER:GetSet("Resolution", 16)
|
||||
BUILDER:GetSet("Width", 1)
|
||||
BUILDER:GetSet("WidthBend", 0)
|
||||
BUILDER:GetSet("WidthBendSize", 1)
|
||||
BUILDER:GetSet("StartWidthMultiplier", 1)
|
||||
BUILDER:GetSet("EndWidthMultiplier", 1)
|
||||
BUILDER:GetSet("TextureStretch", 1)
|
||||
BUILDER:GetSet("TextureScroll", 0)
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("StartColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("EndColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("StartAlpha", 1)
|
||||
BUILDER:GetSet("EndAlpha", 1)
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local found = ("/" .. self:GetMaterial()):match(".*/(.+)")
|
||||
return found and pac.PrettifyName(found:gsub("%..+", "")) or "error"
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetMaterial(self.Material)
|
||||
|
||||
self.StartColorC = Color(255, 255, 255, 255)
|
||||
self.EndColorC = Color(255, 255, 255, 255)
|
||||
end
|
||||
|
||||
function PART:SetStartColor(v)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.r = v.r
|
||||
self.StartColorC.g = v.g
|
||||
self.StartColorC.b = v.b
|
||||
|
||||
self.StartColor = v
|
||||
end
|
||||
|
||||
function PART:SetEndColor(v)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.r = v.r
|
||||
self.EndColorC.g = v.g
|
||||
self.EndColorC.b = v.b
|
||||
|
||||
self.EndColor = v
|
||||
end
|
||||
|
||||
function PART:SetStartAlpha(n)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.a = n * 255
|
||||
|
||||
self.StartAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetEndAlpha(n)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.a = n * 255
|
||||
|
||||
self.EndAlpha = n
|
||||
end
|
||||
|
||||
function PART:FixMaterial()
|
||||
local mat = self.Materialm
|
||||
|
||||
if not mat then return end
|
||||
|
||||
local shader = mat:GetShader()
|
||||
|
||||
if shader == "VertexLitGeneric" or shader == "Cable" then
|
||||
local tex_path = mat:GetString("$basetexture")
|
||||
|
||||
if tex_path then
|
||||
local params = {}
|
||||
|
||||
params["$basetexture"] = tex_path
|
||||
params["$vertexcolor"] = 1
|
||||
params["$vertexalpha"] = 1
|
||||
|
||||
self.Materialm = CreateMaterial(tostring(self) .. "_pac_trail", "UnlitGeneric", params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
self.Material = var
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if isstring(var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:FixMaterial()
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
elseif type(var) == "IMaterial" then
|
||||
self.Materialm = var
|
||||
self:FixMaterial()
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local part = self.EndPoint
|
||||
|
||||
if self.Materialm and self.StartColorC and self.EndColorC and part:IsValid() and part.GetWorldPosition then
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
render.SetMaterial(self.Materialm)
|
||||
pac.DrawBeam(
|
||||
pos,
|
||||
part:GetWorldPosition(),
|
||||
|
||||
ang:Forward(),
|
||||
part:GetWorldAngles():Forward(),
|
||||
|
||||
self.Bend,
|
||||
math.Clamp(self.Resolution, 1, 256),
|
||||
self.Width,
|
||||
self.StartColorC,
|
||||
self.EndColorC,
|
||||
self.Frequency,
|
||||
self.TextureStretch,
|
||||
self.TextureScroll,
|
||||
self.WidthBend,
|
||||
self.WidthBendSize,
|
||||
self.StartWidthMultiplier,
|
||||
self.EndWidthMultiplier
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
328
lua/pac3/core/client/parts/bone.lua
Normal file
328
lua/pac3/core/client/parts/bone.lua
Normal file
@@ -0,0 +1,328 @@
|
||||
--[[
|
||||
| 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 NULL = NULL
|
||||
local pairs = pairs
|
||||
local Matrix = Matrix
|
||||
local vector_origin = vector_origin
|
||||
local Vector = Vector
|
||||
local Angle = Angle
|
||||
|
||||
for _, v in pairs(ents.GetAll()) do
|
||||
v.pac_bone_setup_data = nil
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "bone"
|
||||
PART.ClassName = "bone3"
|
||||
PART.Groups = {'entity', 'model'}
|
||||
PART.Icon = 'icon16/connect.png'
|
||||
PART.is_bone_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("ScaleChildren", false)
|
||||
BUILDER:GetSet("MoveChildrenToOrigin", false)
|
||||
BUILDER:GetSet("FollowAnglesOnly", false)
|
||||
BUILDER:GetSet("HideMesh", false)
|
||||
BUILDER:GetSet("InvertHideMesh", false)
|
||||
BUILDER:GetSetPart("FollowPart")
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1), {editor_sensitivity = 0.25})
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetBone()
|
||||
end
|
||||
|
||||
function PART:SetBone(val)
|
||||
self.Bone = val
|
||||
self.bone_index = self:GetModelBoneIndex(self.Bone)
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBone(self:GetBone())
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent.pac_bone_parts = ent.pac_bone_parts or {}
|
||||
if not table.HasValue(ent.pac_bone_parts, self) then
|
||||
table.insert(ent.pac_bone_parts, self)
|
||||
end
|
||||
|
||||
if ent.pac_build_bone_id then
|
||||
ent:RemoveCallback("BuildBonePositions", ent.pac_build_bone_id)
|
||||
end
|
||||
|
||||
local id
|
||||
id = ent:AddCallback("BuildBonePositions", function(ent, ...)
|
||||
if not self:IsValid() or not ent.pac_bone_parts or not ent.pac_bone_parts[1] then
|
||||
ent:RemoveCallback("BuildBonePositions", id)
|
||||
return
|
||||
end
|
||||
|
||||
for _, bone in ipairs(ent.pac_bone_parts) do
|
||||
bone:BuildBonePositions2(ent)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
ent.pac_build_bone_id = id
|
||||
end
|
||||
|
||||
function PART:OnParent()
|
||||
self:OnShow()
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if ent.pac_bone_parts then
|
||||
for i,v in ipairs(ent.pac_bone_parts) do
|
||||
if v == self then
|
||||
table.remove(ent.pac_bone_parts, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local inf_scale = Vector(math.huge, math.huge, math.huge)
|
||||
|
||||
local function get_children_bones(ent, root_index, bone_count, out)
|
||||
ent:SetLOD(0)
|
||||
for child_index = 0, bone_count - 1 do
|
||||
if ent:GetBoneParent(child_index) == root_index then
|
||||
if ent:GetBoneMatrix(child_index) then
|
||||
table.insert(out, child_index)
|
||||
end
|
||||
get_children_bones(ent, child_index, bone_count, out)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_children_bones_cached(ent, root_index)
|
||||
ent.pac_cached_child_bones = ent.pac_cached_child_bones or {}
|
||||
|
||||
if not ent.pac_cached_child_bones[root_index] then
|
||||
ent.pac_cached_child_bones[root_index] = {}
|
||||
get_children_bones(ent, root_index, ent:GetBoneCount(), ent.pac_cached_child_bones[root_index])
|
||||
end
|
||||
|
||||
return ent.pac_cached_child_bones[root_index]
|
||||
end
|
||||
|
||||
local function scale_children(ent, root_index, bone_count, scale, move_to_origin)
|
||||
for child_index = 0, bone_count - 1 do
|
||||
if ent:GetBoneParent(child_index) == root_index then
|
||||
local m = ent:GetBoneMatrix(child_index)
|
||||
|
||||
if m then
|
||||
if move_to_origin then
|
||||
m:SetTranslation(move_to_origin)
|
||||
end
|
||||
|
||||
m:Scale(scale)
|
||||
ent:SetBoneMatrix(child_index, m)
|
||||
end
|
||||
|
||||
scale_children(ent, child_index, bone_count, scale, move_to_origin)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local temp_matrix_1 = Matrix()
|
||||
local temp_matrix_2 = Matrix()
|
||||
local temp_vector = Vector()
|
||||
local temp_vector_2 = Vector()
|
||||
local temp_angle = Angle()
|
||||
|
||||
local function temp_vector_add(a, b)
|
||||
temp_vector:Set(a)
|
||||
temp_vector:Add(b)
|
||||
return temp_vector
|
||||
end
|
||||
|
||||
local function temp_vector_scale(a, b)
|
||||
temp_vector_2:Set(a)
|
||||
temp_vector_2:Mul(b)
|
||||
return temp_vector_2
|
||||
end
|
||||
|
||||
|
||||
local function temp_angle_add(a, b)
|
||||
temp_angle:Set(a)
|
||||
temp_angle:Add(b)
|
||||
return temp_angle
|
||||
end
|
||||
|
||||
function PART:BuildBonePositions2(ent)
|
||||
local index = self.bone_index
|
||||
|
||||
if not index then return end
|
||||
|
||||
local world_matrix = ent:GetBoneMatrix(index)
|
||||
|
||||
if not world_matrix then return end
|
||||
|
||||
temp_matrix_2:Set(world_matrix)
|
||||
local unmodified_world_matrix = temp_matrix_2
|
||||
|
||||
self.bone_matrix = self.bone_matrix or Matrix()
|
||||
self.bone_matrix:Set(unmodified_world_matrix)
|
||||
|
||||
if self.FollowPart:IsValid() and self.FollowPart.GetWorldPosition then
|
||||
local pos, ang
|
||||
if self.FollowPart.ClassName == "jiggle" then
|
||||
pos = self.FollowPart.pos
|
||||
ang = self.FollowPart.ang
|
||||
else
|
||||
pos = self.FollowPart:GetWorldPosition()
|
||||
ang = self.FollowPart:GetWorldAngles()
|
||||
end
|
||||
|
||||
if not self.FollowAnglesOnly then
|
||||
world_matrix:SetTranslation(pos)
|
||||
end
|
||||
|
||||
world_matrix:SetAngles(temp_angle_add(ang, self.AngleOffset))
|
||||
world_matrix:Rotate(self.Angles)
|
||||
else
|
||||
world_matrix:Translate(temp_vector_add(self.Position, self.PositionOffset))
|
||||
world_matrix:Rotate(temp_angle_add(self.Angles, self.AngleOffset))
|
||||
end
|
||||
|
||||
local scale = temp_vector_scale(self.Scale, self.Size)
|
||||
|
||||
if self.ScaleChildren or self.MoveChildrenToOrigin then
|
||||
local scale_origin = self.MoveChildrenToOrigin and unmodified_world_matrix:GetTranslation()
|
||||
|
||||
for _, child_index in ipairs(get_children_bones_cached(ent, index)) do
|
||||
local world_matrix = ent:GetBoneMatrix(child_index)
|
||||
if not world_matrix then continue end
|
||||
|
||||
if scale_origin then
|
||||
world_matrix:SetTranslation(scale_origin)
|
||||
end
|
||||
|
||||
if self.ScaleChildren then
|
||||
world_matrix:Scale(scale)
|
||||
end
|
||||
|
||||
ent:SetBoneMatrix(child_index, world_matrix)
|
||||
end
|
||||
end
|
||||
|
||||
local parent_world_matrix = world_matrix
|
||||
unmodified_world_matrix:Invert()
|
||||
local last_inverted_world_matrix = unmodified_world_matrix
|
||||
|
||||
for _, child_index in ipairs(get_children_bones_cached(ent, index)) do
|
||||
local child_world_matrix = ent:GetBoneMatrix(child_index)
|
||||
if not child_world_matrix then continue end
|
||||
|
||||
temp_matrix_1:Set(parent_world_matrix)
|
||||
temp_matrix_1:Mul(last_inverted_world_matrix)
|
||||
temp_matrix_1:Mul(child_world_matrix)
|
||||
|
||||
local world_matrix = temp_matrix_1
|
||||
|
||||
ent:SetBoneMatrix(child_index, world_matrix)
|
||||
|
||||
parent_world_matrix = world_matrix
|
||||
|
||||
child_world_matrix:Invert()
|
||||
last_inverted_world_matrix = child_world_matrix
|
||||
end
|
||||
|
||||
world_matrix:Scale(scale)
|
||||
|
||||
ent:SetBoneMatrix(index, world_matrix)
|
||||
|
||||
if self.HideMesh then
|
||||
local inf_scale = inf_scale
|
||||
|
||||
if ent.GetRagdollEntity and ent:GetRagdollEntity():IsValid() then
|
||||
inf_scale = vector_origin
|
||||
end
|
||||
|
||||
ent.pac_inf_scale = true
|
||||
|
||||
if self.InvertHideMesh then
|
||||
local count = ent:GetBoneCount()
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if i ~= index then
|
||||
ent:ManipulateBoneScale(i, inf_scale)
|
||||
end
|
||||
end
|
||||
else
|
||||
ent:ManipulateBoneScale(index, inf_scale)
|
||||
end
|
||||
else
|
||||
ent.pac_inf_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return Vector(), Angle() end
|
||||
|
||||
if not self.bone_index then return ent:GetPos(), ent:GetAngles() end
|
||||
|
||||
local m = ent:GetBoneMatrix(self.bone_index)
|
||||
if not m then return ent:GetPos(), ent:GetAngles() end
|
||||
|
||||
local pos = m:GetTranslation()
|
||||
local ang = m:GetAngles()
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function PART:GetBoneMatrix()
|
||||
return self.bone_matrix or Matrix()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
|
||||
pac.AddHook("OnEntityCreated", "hide_mesh_no_crash", function(ent)
|
||||
local ply = ent:GetRagdollOwner()
|
||||
if ply:IsPlayer() and ply.pac_inf_scale then
|
||||
for i = 0, ply:GetBoneCount() - 1 do
|
||||
local scale = ply:GetManipulateBoneScale(i)
|
||||
if scale == inf_scale then
|
||||
scale = Vector(0,0,0)
|
||||
end
|
||||
ply:ManipulateBoneScale(i, scale)
|
||||
end
|
||||
end
|
||||
end)
|
||||
86
lua/pac3/core/client/parts/camera.lua
Normal file
86
lua/pac3/core/client/parts/camera.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
--[[
|
||||
| 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 LerpAngle = LerpAngle
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.ClassName = "camera"
|
||||
PART.Group = 'entity'
|
||||
PART.Icon = 'icon16/camera.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("EyeAnglesLerp", 1)
|
||||
BUILDER:GetSet("DrawViewModel", false)
|
||||
|
||||
BUILDER:GetSet("NearZ", -1)
|
||||
BUILDER:GetSet("FarZ", -1)
|
||||
BUILDER:GetSet("FOV", -1)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
for i, ply in ipairs(player.GetAll()) do
|
||||
ply.pac_cameras = nil
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
owner.pac_cameras = owner.pac_cameras or {}
|
||||
owner.pac_cameras[self] = self
|
||||
end
|
||||
|
||||
function PART:CalcView(_, _, eyeang, fov, nearz, farz)
|
||||
local pos, ang = self:GetDrawPosition(nil, true)
|
||||
|
||||
ang = LerpAngle(self.EyeAnglesLerp, ang, eyeang)
|
||||
|
||||
if self.NearZ > 0 then
|
||||
nearz = self.NearZ
|
||||
end
|
||||
|
||||
if self.FarZ > 0 then
|
||||
farz = self.FarZ
|
||||
end
|
||||
|
||||
if self.FOV > 0 then
|
||||
fov = self.FOV
|
||||
end
|
||||
|
||||
return pos, ang, fov, nearz, farz
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
|
||||
local temp = {}
|
||||
|
||||
pac.AddHook("CalcView", "camera_part", function(ply, pos, ang, fov, nearz, farz)
|
||||
if not ply.pac_cameras then return end
|
||||
if ply:GetViewEntity() ~= ply then return end
|
||||
|
||||
for _, part in pairs(ply.pac_cameras) do
|
||||
if part:IsValid() then
|
||||
part:CalcShowHide()
|
||||
|
||||
if not part:IsHidden() then
|
||||
pos, ang, fov, nearz, farz = part:CalcView(ply, pos, ang, fov, nearz, farz)
|
||||
temp.origin = pos
|
||||
temp.angles = ang
|
||||
temp.fov = fov
|
||||
temp.znear = nearz
|
||||
temp.zfar = farz
|
||||
temp.drawviewer = not part.DrawViewModel
|
||||
return temp
|
||||
end
|
||||
else
|
||||
ply.pac_cameras[part] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
94
lua/pac3/core/client/parts/censor.lua
Normal file
94
lua/pac3/core/client/parts/censor.lua
Normal file
@@ -0,0 +1,94 @@
|
||||
--[[
|
||||
| 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_drawable")
|
||||
|
||||
PART.ClassName = "woohoo"
|
||||
PART.Group = "effects"
|
||||
PART.Icon = "icon16/webcam_delete.png"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Resolution", 8)
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("FixedSize", true)
|
||||
BUILDER:GetSet("BlurFiltering", false)
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local render_ReadPixel = render.ReadPixel
|
||||
local surface_SetDrawColor = surface.SetDrawColor
|
||||
local surface_DrawRect = surface.DrawRect
|
||||
local render_CapturePixels = render.CapturePixels
|
||||
|
||||
local x2, y2
|
||||
local r,g,b
|
||||
|
||||
function PART:SetSize(size)
|
||||
self.Size = math.Clamp(size, 1, 32)
|
||||
end
|
||||
|
||||
local function create_rt(self)
|
||||
self.rt = GetRenderTargetEx(
|
||||
"pac3_woohoo_rt_" .. math.Round(self.Resolution) .. "_" .. tostring(self.BlurFiltering),
|
||||
self.Resolution,
|
||||
self.Resolution,
|
||||
RT_SIZE_NO_CHANGE,
|
||||
MATERIAL_RT_DEPTH_NONE,
|
||||
self.BlurFiltering and 2 or 1, -- TEXTUREFLAGS_POINTSAMPLE,
|
||||
CREATERENDERTARGETFLAGS_AUTOMIPMAP,
|
||||
IMAGE_FORMAT_RGB565
|
||||
)
|
||||
|
||||
collectgarbage()
|
||||
end
|
||||
|
||||
function PART:SetBlurFiltering(b)
|
||||
self.BlurFiltering = b
|
||||
create_rt(self)
|
||||
end
|
||||
|
||||
function PART:SetResolution(num)
|
||||
local old = self.Resolution
|
||||
self.Resolution = math.Clamp(num, 4, 1024)
|
||||
|
||||
if not old or math.Round(old) ~= math.Round(self.Resolution) then
|
||||
create_rt(self)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not self.rt then create_rt(self) end
|
||||
|
||||
render.CopyTexture(render.GetScreenEffectTexture(), self.rt)
|
||||
|
||||
cam.Start2D()
|
||||
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
local spos = pos:ToScreen()
|
||||
local size = self.Size
|
||||
|
||||
if self.FixedSize then
|
||||
size = size / pos:Distance(pac.EyePos) * 100
|
||||
end
|
||||
|
||||
size = size * 64
|
||||
|
||||
local x, y, w, h = spos.x-size, spos.y-size, spos.x + size, spos.y + size
|
||||
|
||||
render.SetScissorRect(x,y,w,h, true)
|
||||
render.DrawTextureToScreenRect(self.rt, 0, 0, ScrW(), ScrH())
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
68
lua/pac3/core/client/parts/clip.lua
Normal file
68
lua/pac3/core/client/parts/clip.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
--[[
|
||||
| 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 render_EnableClipping = render.EnableClipping
|
||||
local render_PushCustomClipPlane = render.PushCustomClipPlane
|
||||
local LocalToWorld = LocalToWorld
|
||||
local IsEntity = IsEntity
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "clip"
|
||||
PART.ClassName = "clip2"
|
||||
PART.Groups = {'model', 'modifiers'}
|
||||
PART.Icon = 'icon16/cut.png'
|
||||
|
||||
function PART:OnParent(part)
|
||||
if not part.AddModifier then return end
|
||||
part:AddModifier(self)
|
||||
|
||||
|
||||
-- this is only really for halos..
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
function ent.pacDrawModel(ent)
|
||||
self:PreOnDraw()
|
||||
ent:DrawModel()
|
||||
self:PostOnDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
if not part:IsValid() then return end
|
||||
if not part.RemoveModifier then return end
|
||||
|
||||
part:RemoveModifier(self)
|
||||
end
|
||||
|
||||
do
|
||||
local bclip
|
||||
|
||||
function PART:PreOnDraw()
|
||||
bclip = render_EnableClipping(true)
|
||||
|
||||
local pos, ang = LocalToWorld(self.Position + self.PositionOffset, self:CalcAngles(self.Angles + self.AngleOffset), self:GetBonePosition())
|
||||
local normal = ang:Forward()
|
||||
|
||||
render_PushCustomClipPlane(normal, normal:Dot(pos))
|
||||
end
|
||||
|
||||
local render_PopCustomClipPlane = render.PopCustomClipPlane
|
||||
|
||||
function PART:PostOnDraw()
|
||||
render_PopCustomClipPlane()
|
||||
|
||||
render_EnableClipping(bclip)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
102
lua/pac3/core/client/parts/command.lua
Normal file
102
lua/pac3/core/client/parts/command.lua
Normal file
@@ -0,0 +1,102 @@
|
||||
--[[
|
||||
| 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 = "command"
|
||||
|
||||
PART.Group = "advanced"
|
||||
PART.Icon = "icon16/application_xp_terminal.png"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("String", "", {editor_panel = "string"})
|
||||
BUILDER:GetSet("UseLua", false)
|
||||
BUILDER:GetSet("ExecuteOnWear", false)
|
||||
BUILDER:GetSet("ExecuteOnShow", true)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local sv_allowcslua = GetConVar("sv_allowcslua")
|
||||
local function canRunLua()
|
||||
return sv_allowcslua:GetBool() or pac.AllowClientsideLUA
|
||||
end
|
||||
|
||||
function PART:OnWorn()
|
||||
if self:GetExecuteOnWear() then
|
||||
self:Execute()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering and self:GetExecuteOnShow() then
|
||||
self:Execute()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetUseLua(b)
|
||||
self.UseLua = b
|
||||
self:SetString(self:GetString())
|
||||
end
|
||||
|
||||
function PART:SetString(str)
|
||||
if self.UseLua and canRunLua() and self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
self.func = CompileString(str, "pac_event")
|
||||
end
|
||||
|
||||
self.String = str
|
||||
end
|
||||
|
||||
function PART:GetCode()
|
||||
return self.String
|
||||
end
|
||||
|
||||
function PART:SetCode(str)
|
||||
self.String = str
|
||||
end
|
||||
|
||||
function PART:ShouldHighlight(str)
|
||||
return _G[str] ~= nil
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
if self.UseLua then
|
||||
return ("lua: " .. self.String)
|
||||
end
|
||||
return "command: " .. self.String
|
||||
end
|
||||
|
||||
function PART:Execute()
|
||||
local ent = self:GetPlayerOwner()
|
||||
|
||||
if ent == pac.LocalPlayer then
|
||||
if self.UseLua and self.func then
|
||||
if canRunLua() then
|
||||
local status, err = pcall(self.func)
|
||||
|
||||
if not status then
|
||||
self:SetError(err)
|
||||
ErrorNoHalt(err .. "\n")
|
||||
end
|
||||
else
|
||||
local msg = "clientside lua is disabled (sv_allowcslua 0)"
|
||||
self:SetError(msg)
|
||||
pac.Message(tostring(self) .. " - ".. msg)
|
||||
end
|
||||
else
|
||||
if hook.Run("PACCanRunConsoleCommand", self.String) == false then return end
|
||||
if IsConCommandBlocked(self.String) then
|
||||
self:SetError("Concommand is blocked")
|
||||
return
|
||||
end
|
||||
ent:ConCommand(self.String)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
195
lua/pac3/core/client/parts/custom_animation.lua
Normal file
195
lua/pac3/core/client/parts/custom_animation.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
| 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 animations = pac.animations
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
PART.ClassName = "custom_animation"
|
||||
|
||||
PART.Group = 'advanced'
|
||||
PART.Icon = 'icon16/film.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("URL", "")
|
||||
BUILDER:GetSet("Data", "")
|
||||
BUILDER:GetSet("StopOnHide", true)
|
||||
BUILDER:GetSet("StopOtherAnimations", false)
|
||||
BUILDER:GetSet("AnimationType", "sequence", {enums = {
|
||||
gesture = "gesture",
|
||||
posture = "posture",
|
||||
sequence = "sequence",
|
||||
stance = "stance",
|
||||
}})
|
||||
BUILDER:GetSet("Interpolation", "cosine", {enums = {
|
||||
linear = "linear",
|
||||
cosine = "cosine",
|
||||
cubic = "cubic",
|
||||
none = "none",
|
||||
}})
|
||||
BUILDER:GetSet("Rate", 1)
|
||||
BUILDER:GetSet("BonePower", 1)
|
||||
BUILDER:GetSet("Offset", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
return pac.PrettifyName(("/".. self:GetURL()):match(".+/(.-)%.")) or "no anim"
|
||||
end
|
||||
|
||||
function PART:GetAnimID()
|
||||
return "pac_anim_" .. (self:GetPlayerOwnerId() or "null") .. "_" .. self:GetUniqueID()
|
||||
end
|
||||
|
||||
function PART:GetLuaAnimation()
|
||||
local owner = self:GetOwner()
|
||||
if owner:IsValid() and owner.pac_animations then
|
||||
return owner.pac_animations[self:GetAnimID()]
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetRate(num)
|
||||
self.Rate = num
|
||||
local anim = self:GetLuaAnimation()
|
||||
if anim then
|
||||
anim.TimeScale = self.Rate
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetBonePower(num)
|
||||
self.BonePower = num
|
||||
local anim = self:GetLuaAnimation()
|
||||
if anim then
|
||||
anim.Power = self.BonePower
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetInterpolation(mode)
|
||||
self.Interpolation = mode
|
||||
local anim = self:GetLuaAnimation()
|
||||
if anim then
|
||||
anim.Interpolation = mode
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetOffset(num)
|
||||
self.Offset = num
|
||||
local anim = self:GetLuaAnimation()
|
||||
if anim then
|
||||
anim.Offset = num
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetURL(url)
|
||||
self.URL = url
|
||||
self:SetError()
|
||||
|
||||
if url:find("http") then
|
||||
pac.HTTPGet(url, function(str)
|
||||
local tbl = util.JSONToTable(str)
|
||||
if not tbl then
|
||||
pac.Message("Animation failed to parse from ", url)
|
||||
self:SetError("Animation failed to parse from " .. url)
|
||||
return
|
||||
end
|
||||
|
||||
animations.ConvertOldData(tbl)
|
||||
|
||||
self:SetAnimationType(tbl.Type)
|
||||
self:SetInterpolation(tbl.Interpolation)
|
||||
|
||||
animations.RegisterAnimation(self:GetAnimID(), tbl)
|
||||
|
||||
if pace and pace.timeline.IsActive() and pace.timeline.animation_part == self then
|
||||
pace.timeline.Load(tbl)
|
||||
end
|
||||
end,
|
||||
function(err)
|
||||
if self:IsValid() and pac.LocalPlayer == self:GetPlayerOwner() and pace and pace.IsActive() then
|
||||
if pace and pace.current_part == self and not IsValid(pace.BusyWithProperties) then
|
||||
pace.MessagePrompt(err, "HTTP Request Failed for " .. url, "OK")
|
||||
else
|
||||
local msg = "HTTP Request failed for " .. url .. " - " .. err
|
||||
self:SetError(msg)
|
||||
pac.Message(Color(0, 255, 0), "[animation] ", Color(255, 255, 255), msg)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetData(str)
|
||||
self.Data = str
|
||||
if str then
|
||||
local tbl = util.JSONToTable(str)
|
||||
if tbl then
|
||||
|
||||
if isnumber(tbl.Type) then
|
||||
animations.ConvertOldData(tbl)
|
||||
self:SetAnimationType(tbl.Type)
|
||||
self:SetInterpolation(tbl.Interpolation)
|
||||
end
|
||||
|
||||
animations.RegisterAnimation(self:GetAnimID(), tbl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not animations.GetRegisteredAnimations()[self:GetAnimID()] then
|
||||
self:SetURL(self:GetURL())
|
||||
end
|
||||
|
||||
if owner:IsValid() then
|
||||
if not self:GetStopOnHide() then
|
||||
if animations.GetRegisteredAnimations()[self:GetAnimID()] then
|
||||
animations.StopEntityAnimation(owner, self:GetAnimID())
|
||||
end
|
||||
end
|
||||
animations.SetEntityAnimation(owner, self:GetAnimID())
|
||||
self:SetOffset(self:GetOffset())
|
||||
self:SetRate(self:GetRate())
|
||||
self:SetBonePower(self:GetBonePower())
|
||||
self:SetInterpolation(self:GetInterpolation())
|
||||
if self.StopOtherAnimations and owner.pac_animations then
|
||||
for id in pairs(owner.pac_animations) do
|
||||
if id ~= self:GetAnimID() then
|
||||
animations.StopEntityAnimation(owner, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
--stop animation
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() and self:GetStopOnHide() then
|
||||
if animations.GetRegisteredAnimations()[self:GetAnimID()] then
|
||||
animations.StopEntityAnimation(owner, self:GetAnimID())
|
||||
end
|
||||
animations.ResetEntityBoneMatrix(owner)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
animations.StopEntityAnimation(owner, self:GetAnimID())
|
||||
animations.ResetEntityBoneMatrix(owner)
|
||||
end
|
||||
|
||||
animations.GetRegisteredAnimations()[self:GetAnimID()] = nil
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
59
lua/pac3/core/client/parts/decal.lua
Normal file
59
lua/pac3/core/client/parts/decal.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--!lc util.DecalEx(Material("sprites/key_0"), this:IsValid() and this or Entity(0), there + trace.Normal, -trace.HitNormal, Color(255,255,255,255), 0.5,0.5)
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.ClassName = "decal"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/paintbrush.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
--BUILDER:GetSet("Width", 1)
|
||||
--BUILDER:GetSet("Height", 1)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Material", "")
|
||||
BUILDER:GetSet("IgnoreOwner", true)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
self.Material = var
|
||||
if not pac.Handleurltex(self, var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
if self.Materialm then
|
||||
local filter
|
||||
if self.IgnoreOwner then
|
||||
filter = ents.FindInSphere(pos, 100)
|
||||
end
|
||||
local data = util.TraceLine({start = pos, endpos = pos + (ang:Forward() * 1000), filter = filter})
|
||||
|
||||
if data.Hit then
|
||||
|
||||
util.DecalEx(
|
||||
self.Materialm,
|
||||
data.Entity:IsValid() and data.Entity or Entity(0),
|
||||
data.HitPos + data.Normal,
|
||||
-data.HitNormal,
|
||||
Color(self.Color.x, self.Color.y, self.Color.z, self.Alpha*255),
|
||||
1, 1 -- they don't do anything?
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
227
lua/pac3/core/client/parts/effect.lua
Normal file
227
lua/pac3/core/client/parts/effect.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
--[[
|
||||
| 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 CurTime = CurTime
|
||||
local ParticleEffect = ParticleEffect
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "effect"
|
||||
PART.Groups = {'effects', 'model', 'entity'}
|
||||
PART.Icon = 'icon16/wand.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Effect", "default", {enums = function() return pac.particle_list end})
|
||||
BUILDER:GetSet("Loop", true)
|
||||
BUILDER:GetSet("Follow", true)
|
||||
BUILDER:GetSet("Rate", 1, {editor_sensitivity = 0.1})
|
||||
BUILDER:GetSet("UseParticleTracer", false)
|
||||
|
||||
BUILDER:GetSetPart("PointA")
|
||||
BUILDER:GetSetPart("PointB")
|
||||
BUILDER:GetSetPart("PointC")
|
||||
BUILDER:GetSetPart("PointD")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Translucent")
|
||||
PART.Translucent = false -- otherwise OnDraw won't be called
|
||||
|
||||
local BaseClass_GetOwner = PART.GetOwner
|
||||
|
||||
function PART:GetNiceName()
|
||||
return pac.PrettifyName(self:GetEffect())
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetEffect(self.Effect)
|
||||
|
||||
if not pac.particle_list then
|
||||
local found = {}
|
||||
|
||||
for file_name in pairs(pac_loaded_particle_effects) do
|
||||
local ok, err = pcall(function()
|
||||
local data = file.Read("particles/"..file_name, "GAME", "b")
|
||||
if data then
|
||||
for str in data:gmatch("\3%c([%a_]+)%c") do
|
||||
if #str > 1 then
|
||||
found[str] = str
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
local msg = "unable to parse particle file " .. file_name .. ": " .. err
|
||||
self:SetError(msg)
|
||||
pac.Message(Color(255, 50, 50), msg)
|
||||
end
|
||||
end
|
||||
|
||||
pac.particle_list = found
|
||||
end
|
||||
end
|
||||
|
||||
PART.last_spew = 0
|
||||
|
||||
if not pac_loaded_particle_effects then
|
||||
pac_loaded_particle_effects = {}
|
||||
|
||||
for _, file_name in pairs(file.Find("particles/*.pcf", "GAME")) do
|
||||
if not pac_loaded_particle_effects[file_name] and not pac.BlacklistedParticleSystems[file_name:lower()] then
|
||||
game.AddParticles("particles/" .. file_name)
|
||||
end
|
||||
|
||||
pac_loaded_particle_effects[file_name] = true
|
||||
end
|
||||
end
|
||||
|
||||
local already = {}
|
||||
local alreadyServer = {}
|
||||
local function pac_request_precache(name)
|
||||
if already[name] then return end
|
||||
already[name] = true
|
||||
PrecacheParticleSystem(name)
|
||||
net.Start("pac_request_precache")
|
||||
net.WriteString(name)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function PART:SetEffect(name)
|
||||
self.waitingForServer = true
|
||||
self.Effect = name
|
||||
self.Ready = alreadyServer[name] or false
|
||||
|
||||
if not alreadyServer[name] then
|
||||
pac_request_precache(name)
|
||||
else
|
||||
self.waitingForServer = false
|
||||
end
|
||||
end
|
||||
|
||||
pac.AddHook("pac_EffectPrecached", "pac_Effects", function(name)
|
||||
if alreadyServer[name] then return end
|
||||
alreadyServer[name] = true
|
||||
pac.dprint("effect %q precached!", name)
|
||||
pac.CallRecursiveOnAllParts("OnEffectPrecached", name)
|
||||
end)
|
||||
|
||||
function PART:OnEffectPrecached(name)
|
||||
if self.Effect == name then
|
||||
self.Ready = true
|
||||
self.waitingForServer = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not self.Ready then
|
||||
if not self.waitingForServer then
|
||||
self:SetEffect(self.Effect)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and self.Loop then
|
||||
local time = CurTime()
|
||||
if self.last_spew < time then
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
ent:StopParticles()
|
||||
ent:StopParticleEmission()
|
||||
self:Emit(pos, ang)
|
||||
self.last_spew = time + math.max(self.Rate, 0.1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent:StopParticles()
|
||||
ent:StopParticleEmission()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if from_rendering then
|
||||
self:Emit(self:GetDrawPosition())
|
||||
end
|
||||
end
|
||||
|
||||
function PART:Emit(pos, ang)
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if not self.Effect then
|
||||
ent:StopParticles()
|
||||
ent:StopParticleEmission()
|
||||
return
|
||||
end
|
||||
|
||||
if self.UseParticleTracer and self.PointA:IsValid() then
|
||||
local ent2 = self.PointA.Entity and self.PointA.Entity or self.PointA:GetOwner()
|
||||
|
||||
util.ParticleTracerEx(
|
||||
self.Effect,
|
||||
ent:GetPos(),
|
||||
ent2:GetPos(),
|
||||
true,
|
||||
ent:EntIndex(),
|
||||
0
|
||||
)
|
||||
return
|
||||
end
|
||||
|
||||
if self.PointA:IsValid() then
|
||||
local points = {}
|
||||
|
||||
table.insert(points, {
|
||||
entity = self.PointA.Entity and self.PointA.Entity or self.PointA:GetOwner(),
|
||||
attachtype = PATTACH_ABSORIGIN_FOLLOW,
|
||||
})
|
||||
|
||||
if self.PointB:IsValid() then
|
||||
table.insert(points, {
|
||||
entity = self.PointB.Entity and self.PointB.Entity or self.PointB:GetOwner(),
|
||||
attachtype = PATTACH_ABSORIGIN_FOLLOW,
|
||||
})
|
||||
end
|
||||
|
||||
if self.PointC:IsValid() then
|
||||
table.insert(points, {
|
||||
entity = self.PointC.Entity and self.PointC.Entity or self.PointC:GetOwner(),
|
||||
attachtype = PATTACH_ABSORIGIN_FOLLOW,
|
||||
})
|
||||
end
|
||||
|
||||
if self.PointD:IsValid() then
|
||||
table.insert(points, {
|
||||
entity = self.PointD.Entity and self.PointD.Entity or self.PointD:GetOwner(),
|
||||
attachtype = PATTACH_ABSORIGIN_FOLLOW,
|
||||
})
|
||||
end
|
||||
|
||||
ent:CreateParticleEffect(self.Effect, points)
|
||||
elseif self.Follow then
|
||||
ent:StopParticles()
|
||||
ent:StopParticleEmission()
|
||||
CreateParticleSystem(ent, self.Effect, PATTACH_ABSORIGIN_FOLLOW, 0)
|
||||
else
|
||||
ent:StopParticles()
|
||||
ent:StopParticleEmission()
|
||||
ParticleEffect(self.Effect, pos, ang, ent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
2220
lua/pac3/core/client/parts/event.lua
Normal file
2220
lua/pac3/core/client/parts/event.lua
Normal file
File diff suppressed because it is too large
Load Diff
205
lua/pac3/core/client/parts/faceposer.lua
Normal file
205
lua/pac3/core/client/parts/faceposer.lua
Normal file
@@ -0,0 +1,205 @@
|
||||
--[[
|
||||
| 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 = "faceposer"
|
||||
|
||||
PART.FriendlyName = "face poser"
|
||||
PART.Icon = 'icon16/monkey.png'
|
||||
PART.Group = 'entity'
|
||||
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:GetSet("Preset", "", {enums = function(part)
|
||||
local ent = part:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
local maps = {}
|
||||
|
||||
local toolgun = {}
|
||||
for i = 0, 255 do
|
||||
local name = ent:GetFlexName(i)
|
||||
if name then
|
||||
toolgun[name] = GetConVar("faceposer_flex" .. i):GetFloat()
|
||||
end
|
||||
end
|
||||
|
||||
maps.toolgun = util.TableToJSON({
|
||||
scale = GetConVar("faceposer_scale"):GetFloat(),
|
||||
weight_map = util.TableToJSON(toolgun),
|
||||
})
|
||||
|
||||
for preset_name, map in pairs(presets.GetTable( "face" )) do
|
||||
local preset = {}
|
||||
for key, weight in pairs(map) do
|
||||
local i = tonumber(key:match("faceposer_flex(%d+)"))
|
||||
if i then
|
||||
local name = ent:GetFlexName(i)
|
||||
if name then
|
||||
preset[name] = tonumber(weight)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
maps[preset_name] = util.TableToJSON({
|
||||
scale = tonumber(map.faceposer_scale),
|
||||
weight_map = util.TableToJSON(preset),
|
||||
})
|
||||
end
|
||||
|
||||
return maps
|
||||
end})
|
||||
:GetSet("FlexWeights", "", {hidden = true})
|
||||
:GetSet("Scale", 1)
|
||||
:GetSet("Additive", false)
|
||||
:EndStorableVars()
|
||||
|
||||
|
||||
-- Make the internal flex names be more presentable, TODO: handle numbers
|
||||
local function PrettifyName( name )
|
||||
name = name:Replace( "_", " " )
|
||||
|
||||
-- Try to split text into words, where words would start with single uppercase character
|
||||
local newParts = {}
|
||||
for id, str in pairs( string.Explode( " ", name ) ) do
|
||||
local wordStart = 1
|
||||
for i = 2, str:len() do
|
||||
local c = str[ i ]
|
||||
if ( c:upper() == c ) then
|
||||
local toAdd = str:sub(wordStart, i - 1)
|
||||
if ( toAdd:upper() == toAdd ) then continue end
|
||||
table.insert( newParts, toAdd )
|
||||
wordStart = i
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.insert( newParts, str:sub(wordStart, str:len()))
|
||||
end
|
||||
|
||||
-- Uppercase all first characters
|
||||
for id, str in pairs( newParts ) do
|
||||
if ( str:len() < 2 ) then continue end
|
||||
newParts[ id ] = str:Left( 1 ):upper() .. str:sub( 2 )
|
||||
end
|
||||
|
||||
return table.concat( newParts, " " )
|
||||
end
|
||||
|
||||
|
||||
function PART:GetDynamicProperties()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
if ent.GetFlexNum and ent:GetFlexNum() and ent:GetFlexNum() == 0 then return end
|
||||
|
||||
local tbl = {}
|
||||
|
||||
for i = 0, ent:GetFlexNum() - 1 do
|
||||
local name = ent:GetFlexName(i)
|
||||
|
||||
tbl[name] = {
|
||||
key = name,
|
||||
sort_key = -i,
|
||||
get = function()
|
||||
local weight_map = util.JSONToTable(self:GetFlexWeights()) or {}
|
||||
|
||||
return weight_map[name] or 0
|
||||
end,
|
||||
set = function(val)
|
||||
local weight_map = util.JSONToTable(self:GetFlexWeights()) or {}
|
||||
|
||||
weight_map[name] = tonumber(val) or 0
|
||||
|
||||
self:SetFlexWeights(util.TableToJSON(weight_map))
|
||||
end,
|
||||
udata = {
|
||||
editor_friendly = PrettifyName(name),
|
||||
group = "flexes",
|
||||
editor_sensitivity = 0.1,
|
||||
editor_onchange = function(self, num)
|
||||
local min, max = ent:GetFlexBounds(i)
|
||||
|
||||
return math.Clamp(num, min, max)
|
||||
end,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
function PART:SetPreset(json)
|
||||
local preset = util.JSONToTable(json)
|
||||
if preset then
|
||||
self:SetFlexWeights(preset.weight_map)
|
||||
self:SetScale(preset.scale)
|
||||
end
|
||||
self.Preset = ""
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
return "face pose"
|
||||
end
|
||||
|
||||
function PART:GetWeightMap()
|
||||
local data = self:GetFlexWeights()
|
||||
|
||||
if data ~= self.last_data then
|
||||
self.weight_map = util.JSONToTable(data) or {}
|
||||
self.last_data = data
|
||||
end
|
||||
|
||||
return self.weight_map
|
||||
end
|
||||
|
||||
function PART:UpdateFlex()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent:SetFlexScale(self.Scale)
|
||||
ent.pac_touching_flexes = ent.pac_touching_flexes or {}
|
||||
|
||||
for name, weight in pairs(self:GetWeightMap()) do
|
||||
local id = ent:GetFlexIDByName(name)
|
||||
if id then
|
||||
if self.Additive then
|
||||
weight = ent:GetFlexWeight(id) + weight
|
||||
end
|
||||
ent:SetFlexWeight(id, weight)
|
||||
ent.pac_touching_flexes[id] = pac.RealTime + 0.1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsPlayer() then
|
||||
self:UpdateFlex()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
self:UpdateFlex()
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
self:UpdateFlex()
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self:UpdateFlex()
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
self:UpdateFlex()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
66
lua/pac3/core/client/parts/flex.lua
Normal file
66
lua/pac3/core/client/parts/flex.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| 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 = "flex"
|
||||
|
||||
PART.Icon = 'icon16/emoticon_smile.png'
|
||||
PART.Group = 'entity'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Flex", "", {
|
||||
enums = function(part)
|
||||
local tbl = {}
|
||||
|
||||
for _, v in pairs(pac.GetFlexMap(part:GetOwner())) do
|
||||
tbl[v.name] = v.name
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
})
|
||||
|
||||
BUILDER:GetSet("Weight", 0)
|
||||
BUILDER:GetSet("Additive", false)
|
||||
BUILDER:GetSet("RootOwner", false, { hide_in_editor = true })
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:SetRootOwner(b)
|
||||
self:SetRootOwnerDeprecated(b)
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetFlex() ~= "" and self:GetFlex() or "no flex"
|
||||
end
|
||||
|
||||
function PART:GetFlexID()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() or not ent.GetFlexNum or ent:GetFlexNum() == 0 then return end
|
||||
|
||||
local flex_map = pac.GetFlexMap(ent)
|
||||
local flex = flex_map[self.Flex:lower()]
|
||||
|
||||
return flex and flex.i, ent
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
local id, ent = self:GetFlexID()
|
||||
if not id then return end
|
||||
local weight = self.Weight
|
||||
if self.Additive then
|
||||
weight = weight + ent:GetFlexWeight(id)
|
||||
end
|
||||
ent:SetFlexWeight(id, weight)
|
||||
ent.pac_touching_flexes = ent.pac_touching_flexes or {}
|
||||
ent.pac_touching_flexes[id] = pac.RealTime + 0.1
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
80
lua/pac3/core/client/parts/fog.lua
Normal file
80
lua/pac3/core/client/parts/fog.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--[[
|
||||
| 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 MATERIAL_FOG_NONE = MATERIAL_FOG_NONE
|
||||
local MATERIAL_FOG_LINEAR = MATERIAL_FOG_LINEAR
|
||||
local MATERIAL_FOG_LINEAR_BELOW_FOG_Z = MATERIAL_FOG_LINEAR_BELOW_FOG_Z
|
||||
local render_FogStart = render.FogStart
|
||||
local render_FogEnd = render.FogEnd
|
||||
local render_FogMaxDensity = render.FogMaxDensity
|
||||
local render_SetFogZ = render.SetFogZ
|
||||
local render_FogMode = render.FogMode
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "fog"
|
||||
|
||||
PART.Group = 'modifiers'
|
||||
PART.Icon = 'icon16/weather_clouds.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Start", 0)
|
||||
BUILDER:GetSet("End", 10)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
--BUILDER:GetSet("AffectChildren", false)
|
||||
BUILDER:GetSet("Height", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local h = pac.ColorToNames(self:GetColor())
|
||||
|
||||
return h .. " fog"
|
||||
end
|
||||
|
||||
function PART:SetColor(v)
|
||||
self.Color = v
|
||||
|
||||
self.clr = {v.r, v.g, v.b}
|
||||
end
|
||||
|
||||
function PART:OnParent(part)
|
||||
if part.AddModifier then
|
||||
part:AddModifier(self)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
if not part:IsValid() then return end
|
||||
if part.RemoveModifier then
|
||||
part:RemoveModifier(self)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PreOnDraw()
|
||||
render_FogStart(self.Start * 100)
|
||||
render_FogEnd(self.End * 100)
|
||||
render_FogMaxDensity(self.Alpha)
|
||||
if self.clr then render.FogColor(self.clr[1], self.clr[2], self.clr[3]) end
|
||||
|
||||
if self.Height > 0 then
|
||||
render_FogMode(MATERIAL_FOG_LINEAR_BELOW_FOG_Z)
|
||||
render_SetFogZ(self:GetWorldPosition().z + self.Height * 10)
|
||||
else
|
||||
render_FogMode(MATERIAL_FOG_LINEAR)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function PART:PostOnDraw()
|
||||
render.FogMode(MATERIAL_FOG_NONE)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
125
lua/pac3/core/client/parts/gesture.lua
Normal file
125
lua/pac3/core/client/parts/gesture.lua
Normal file
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
| 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 = "gesture"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = 'entity'
|
||||
PART.Icon = 'icon16/thumb_up.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Loop", false)
|
||||
BUILDER:GetSet("GestureName", "", {editor_panel = "sequence"})
|
||||
BUILDER:GetSet("SlotName", "attackreload", {enums = function(part) return part.ValidGestureSlots end})
|
||||
BUILDER:GetSet("SlotWeight", 1)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
PART.ValidGestureSlots = {
|
||||
attackreload = GESTURE_SLOT_ATTACK_AND_RELOAD,
|
||||
grenade = GESTURE_SLOT_GRENADE,
|
||||
jump = GESTURE_SLOT_JUMP,
|
||||
swim = GESTURE_SLOT_SWIM,
|
||||
flinch = GESTURE_SLOT_FLINCH,
|
||||
vcd = GESTURE_SLOT_VCD,
|
||||
custom = GESTURE_SLOT_CUSTOM
|
||||
}
|
||||
|
||||
function PART:GetSequenceList()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
return ent:GetSequenceList()
|
||||
end
|
||||
|
||||
return {"none"}
|
||||
end
|
||||
|
||||
function PART:GetSlotID()
|
||||
return self.ValidGestureSlots[self.SlotName] or GESTURE_SLOT_CUSTOM
|
||||
end
|
||||
|
||||
function PART:SetLoop(bool)
|
||||
self.Loop = bool
|
||||
|
||||
if not self:IsHidden() then
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetGestureName(name)
|
||||
self.GestureName = name
|
||||
|
||||
local list = name:Split(";")
|
||||
for k,v in next,list do
|
||||
if v:Trim() == "" then list[k] = nil end
|
||||
end
|
||||
|
||||
self.random_gestlist = list
|
||||
|
||||
if not self:IsHidden() then
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSlotName(name)
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() then -- to stop gestures getting stuck
|
||||
for _, v in next,self.ValidGestureSlots do
|
||||
ent:AnimResetGestureSlot(v)
|
||||
end
|
||||
end
|
||||
|
||||
self.SlotName = name
|
||||
|
||||
if not self:IsHidden() then
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSlotWeight(num)
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent:AnimSetGestureWeight(self:GetSlotID(), num)
|
||||
end
|
||||
|
||||
self.SlotWeight = num
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() then -- function is for players only :(
|
||||
local gesture = self.random_gestlist and table.Random(self.random_gestlist) or self.GestureName
|
||||
local slot = self:GetSlotID()
|
||||
|
||||
ent:AnimResetGestureSlot(slot)
|
||||
local act = ent:GetSequenceActivity(ent:LookupSequence(gesture))
|
||||
if act ~= 1 then
|
||||
ent:AnimRestartGesture(slot, act, not self.Loop)
|
||||
end
|
||||
ent:AnimSetGestureWeight(slot, self.SlotWeight or 1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() and self.Loop then
|
||||
ent:AnimResetGestureSlot(self:GetSlotID())
|
||||
end
|
||||
end
|
||||
|
||||
PART.OnRemove = PART.OnHide
|
||||
|
||||
BUILDER:Register()
|
||||
148
lua/pac3/core/client/parts/group.lua
Normal file
148
lua/pac3/core/client/parts/group.lua
Normal file
@@ -0,0 +1,148 @@
|
||||
--[[
|
||||
| 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 = "group"
|
||||
|
||||
PART.Icon = 'icon16/world.png'
|
||||
PART.Description = "right click to add parts"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Duplicate", false)
|
||||
BUILDER:GetSet("OwnerName", "self")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local init_list = {}
|
||||
local init_index = 0
|
||||
|
||||
pac.AddHook("Think", "group_init", function()
|
||||
if init_index == 0 then return end
|
||||
|
||||
for i = 1, init_index do
|
||||
local self = init_list[i]
|
||||
|
||||
if self:IsValid() and not self:HasParent() and not self.Owner:IsValid() and not self.update_owner_once then
|
||||
self:UpdateOwnerName()
|
||||
end
|
||||
end
|
||||
|
||||
init_list = {}
|
||||
init_index = 0
|
||||
end)
|
||||
|
||||
function PART:Initialize()
|
||||
init_index = init_index + 1
|
||||
init_list[init_index] = self
|
||||
end
|
||||
|
||||
function PART:SetOwner(ent)
|
||||
if self:HasParent() then
|
||||
self.Owner = ent or NULL
|
||||
else
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
pac.UnhookEntityRender(owner, self)
|
||||
end
|
||||
|
||||
self.Owner = ent or NULL
|
||||
owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
if not pac.HookEntityRender(owner, self) then
|
||||
self:ShowFromRendering()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:HideInvalidOwners()
|
||||
local prev_owner = self:GetOwner()
|
||||
|
||||
if not prev_owner:IsValid() then
|
||||
self:SetOwner(NULL)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateOwnerName()
|
||||
-- this is only supported by groups in root
|
||||
self.update_owner_once = true
|
||||
if self:HasParent() then return end
|
||||
|
||||
local ent
|
||||
local prev_owner = self:GetOwner()
|
||||
|
||||
if self.Duplicate then
|
||||
ent = pac.HandleOwnerName(self:GetPlayerOwner(), self.OwnerName, ent, self, function(e) return e.pac_duplicate_attach_uid ~= self.UniqueID end) or NULL
|
||||
|
||||
if ent ~= prev_owner and ent:IsValid() then
|
||||
local tbl = self:ToTable()
|
||||
tbl.self.OwnerName = "self"
|
||||
tbl.self.Duplicate = false
|
||||
pac.SetupENT(ent)
|
||||
local part = ent:AttachPACPart(tbl)
|
||||
part:SetShowInEditor(false)
|
||||
ent:CallOnRemove("pac_remove_outfit_" .. tbl.self.UniqueID, function()
|
||||
ent:RemovePACPart(tbl)
|
||||
end)
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
ent:SetPACDrawDistance(0)
|
||||
end
|
||||
|
||||
ent.pac_duplicate_attach_uid = part:GetUniqueID()
|
||||
end
|
||||
else
|
||||
ent = pac.HandleOwnerName(self:GetPlayerOwner(), self.OwnerName, ent, self) or NULL
|
||||
end
|
||||
|
||||
if ent ~= prev_owner then
|
||||
self:SetOwner(ent)
|
||||
end
|
||||
end
|
||||
|
||||
local Base_SetPlayerOwner = PART.SetPlayerOwner
|
||||
|
||||
function PART:SetPlayerOwner(ply)
|
||||
local prev = self.PlayerOwner
|
||||
|
||||
Base_SetPlayerOwner(self, ply)
|
||||
|
||||
if prev:IsValid() then
|
||||
self:UpdateOwnerName()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetOwnerName(name)
|
||||
if name == "" then
|
||||
name = "self"
|
||||
end
|
||||
|
||||
self.OwnerName = name
|
||||
|
||||
if self.Owner:IsValid() then
|
||||
self:UpdateOwnerName()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
return #self:GetChildrenList() .. " children"
|
||||
end
|
||||
|
||||
function PART:OnVehicleChanged(ply, vehicle)
|
||||
if self:HasParent() then return end
|
||||
|
||||
if self.OwnerName == "active vehicle" then
|
||||
self:UpdateOwnerName()
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
94
lua/pac3/core/client/parts/halo.lua
Normal file
94
lua/pac3/core/client/parts/halo.lua
Normal file
@@ -0,0 +1,94 @@
|
||||
--[[
|
||||
| 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 Color = Color
|
||||
local Vector = Vector
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
PART.ClassName = "halo"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = {'effects', 'model'}
|
||||
PART.Icon = 'icon16/shading.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("BlurX", 2)
|
||||
BUILDER:GetSet("BlurY", 2)
|
||||
BUILDER:GetSet("Amount", 1)
|
||||
BUILDER:GetSet("Passes", 1)
|
||||
BUILDER:GetSet("SphericalSize", 1)
|
||||
BUILDER:GetSet("Shape", 1)
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Additive", true)
|
||||
BUILDER:GetSet("IgnoreZ", false)
|
||||
BUILDER:GetSet("AffectChildren", false)
|
||||
BUILDER:GetSet("AffectTargetChildren", false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local h = pac.ColorToNames(self:GetColor())
|
||||
|
||||
return h .. " halo"
|
||||
end
|
||||
|
||||
function PART:SetShape(n)
|
||||
self.Shape = math.Clamp(n, 0, 1)
|
||||
end
|
||||
|
||||
function PART:SetPasses(n)
|
||||
self.Passes = math.min(n, 50)
|
||||
end
|
||||
|
||||
function PART:GetTarget()
|
||||
local parent = self:GetTargetEntity()
|
||||
|
||||
if parent:IsValid() then
|
||||
return parent
|
||||
end
|
||||
|
||||
return self:GetParent()
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
|
||||
local tbl = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
tbl[1] = ent
|
||||
end
|
||||
|
||||
local target = self:GetTarget()
|
||||
|
||||
if self.AffectTargetChildren and target:IsValid() then
|
||||
for _, part in ipairs(target:GetChildrenList()) do
|
||||
local ent = part:GetOwner()
|
||||
if ent:IsValid() and not part:IsHiddenCached() then
|
||||
table.insert(tbl, ent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.AffectChildren then
|
||||
for _, part in ipairs(self:GetChildrenList()) do
|
||||
local ent = part:GetOwner()
|
||||
if ent:IsValid() and not part:IsHiddenCached() then
|
||||
table.insert(tbl, ent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pac.haloex.Add(tbl, Color(self.Color.r, self.Color.g, self.Color.b), self.BlurX, self.BlurY, self.Passes, self.Additive, self.IgnoreZ, self.Amount, self.SphericalSize, self.Shape)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
175
lua/pac3/core/client/parts/holdtype.lua
Normal file
175
lua/pac3/core/client/parts/holdtype.lua
Normal file
@@ -0,0 +1,175 @@
|
||||
--[[
|
||||
| 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 = "holdtype"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = 'entity'
|
||||
PART.Icon = 'icon16/user_edit.png'
|
||||
|
||||
local act_mods =
|
||||
{
|
||||
"ACT_MP_STAND_IDLE",
|
||||
"ACT_MP_WALK",
|
||||
"ACT_MP_RUN",
|
||||
"ACT_MP_CROUCH_IDLE",
|
||||
"ACT_MP_CROUCHWALK",
|
||||
"ACT_MP_ATTACK_STAND_PRIMARYFIRE",
|
||||
"ACT_MP_ATTACK_CROUCH_PRIMARYFIRE",
|
||||
"ACT_MP_RELOAD_STAND",
|
||||
"ACT_MP_RELOAD_CROUCH",
|
||||
"ACT_MP_JUMP",
|
||||
"ACT_LAND",
|
||||
"ACT_RANGE_ATTACK1",
|
||||
"ACT_MP_SWIM_IDLE",
|
||||
"ACT_MP_SWIM",
|
||||
}
|
||||
|
||||
do
|
||||
local temp = {}
|
||||
|
||||
for _, act in pairs(act_mods) do
|
||||
|
||||
local key = act
|
||||
key = "_" .. key
|
||||
key = key:gsub("ACT_MP_", "")
|
||||
key = key :lower()
|
||||
key = key:gsub("_(.)", function(char)
|
||||
return char:upper()
|
||||
end)
|
||||
|
||||
temp[key] = _G[act]
|
||||
end
|
||||
|
||||
-- ew
|
||||
if temp.Crouchwalk then
|
||||
temp.CrouchWalk = temp.Crouchwalk
|
||||
temp.Crouchwalk = nil
|
||||
end
|
||||
|
||||
act_mods = temp
|
||||
end
|
||||
|
||||
PART.ActMods = act_mods
|
||||
|
||||
local udata = {
|
||||
enums = function(part)
|
||||
if not part.GetSequenceList then return {} end -- ???
|
||||
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs(part:GetSequenceList()) do
|
||||
tbl[v] = v
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
}
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
for name in pairs(act_mods) do
|
||||
BUILDER:GetSet(name, "", udata)
|
||||
end
|
||||
|
||||
BUILDER:GetSet("Fallback", "", udata)
|
||||
BUILDER:GetSet("Noclip", "", udata)
|
||||
BUILDER:GetSet("Air", "", udata)
|
||||
BUILDER:GetSet("Sitting", "", udata)
|
||||
BUILDER:GetSet("AlternativeRate", false)
|
||||
BUILDER:GetSet("Override", false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
for name in pairs(act_mods) do
|
||||
PART["Set" .. name] = function(self, str)
|
||||
self[name] = str
|
||||
|
||||
if not self:IsHidden() then
|
||||
self:UpdateActTable()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetFallback(str)
|
||||
self.Fallback = str
|
||||
if not self:IsHidden() then
|
||||
self:UpdateActTable()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateActTable()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent.pac_holdtype_alternative_animation_rate = self.AlternativeRate
|
||||
|
||||
ent.pac_holdtypes = ent.pac_holdtypes or {}
|
||||
|
||||
if self.Override then
|
||||
table.Empty(ent.pac_holdtypes)
|
||||
end
|
||||
|
||||
ent.pac_holdtypes[self] = ent.pac_holdtypes[self] or {}
|
||||
|
||||
local acts = ent.pac_holdtypes[self]
|
||||
|
||||
for name, act in pairs(act_mods) do
|
||||
acts[act] = ent:GetSequenceActivity(ent:LookupSequence(self[name]))
|
||||
end
|
||||
|
||||
-- custom acts
|
||||
acts.fallback = ent:GetSequenceActivity(ent:LookupSequence(self.Fallback))
|
||||
acts.noclip = ent:GetSequenceActivity(ent:LookupSequence(self.Noclip))
|
||||
acts.air = ent:GetSequenceActivity(ent:LookupSequence(self.Air))
|
||||
acts.sitting = ent:GetSequenceActivity(ent:LookupSequence(self.Sitting))
|
||||
|
||||
acts.part = self
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if (ent:GetModel() ~= self.last_model or ent.pac_holdtypes ~= self.last_pac_holdtypes) then
|
||||
self:UpdateActTable()
|
||||
self.last_model = ent:GetModel()
|
||||
self.last_pac_holdtypes = ent.pac_holdtypes
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetSequenceList()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
return ent:GetSequenceList()
|
||||
end
|
||||
|
||||
return {"none"}
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent.pac_holdtypes then
|
||||
ent.pac_holdtypes[self] = nil
|
||||
end
|
||||
|
||||
ent.pac_holdtype_alternative_animation_rate = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self:UpdateActTable()
|
||||
end
|
||||
|
||||
|
||||
BUILDER:Register()
|
||||
21
lua/pac3/core/client/parts/info.lua
Normal file
21
lua/pac3/core/client/parts/info.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
--[[
|
||||
| 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 = "info"
|
||||
|
||||
PART.Group = ''
|
||||
PART.Icon = 'icon16/help.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("SpawnEntity", "")
|
||||
BUILDER:GetSet("UserData", "")
|
||||
BUILDER:EndStorableVars()
|
||||
202
lua/pac3/core/client/parts/jiggle.lua
Normal file
202
lua/pac3/core/client/parts/jiggle.lua
Normal file
@@ -0,0 +1,202 @@
|
||||
--[[
|
||||
| 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 FrameTime = FrameTime
|
||||
local util_QuickTrace = util.QuickTrace
|
||||
local VectorRand = VectorRand
|
||||
local Vector = Vector
|
||||
local Angle = Angle
|
||||
local physenv_GetGravity = physenv.GetGravity
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "jiggle"
|
||||
PART.Group = 'model'
|
||||
PART.Icon = 'icon16/chart_line.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Strain", 0.5, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Clamp(num, 0, 1) * 0.999
|
||||
end})
|
||||
BUILDER:GetSet("Speed", 1)
|
||||
BUILDER:GetSet("ConstantVelocity", Vector(0, 0, 0))
|
||||
BUILDER:GetSet("LocalVelocity", true)
|
||||
BUILDER:GetSet("JiggleAngle", true)
|
||||
BUILDER:GetSet("JigglePosition", true)
|
||||
|
||||
BUILDER:GetSet("ConstrainPitch", false)
|
||||
BUILDER:GetSet("ConstrainYaw", false)
|
||||
BUILDER:GetSet("ConstrainRoll", false)
|
||||
|
||||
BUILDER:GetSet("ConstrainX", false)
|
||||
BUILDER:GetSet("ConstrainY", false)
|
||||
BUILDER:GetSet("ConstrainZ", false)
|
||||
|
||||
BUILDER:GetSet("ConstrainSphere", 0)
|
||||
BUILDER:GetSet("StopRadius", 0)
|
||||
BUILDER:GetSet("Ground", false)
|
||||
BUILDER:GetSet("ResetOnHide", false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local math_AngleDifference = math.AngleDifference
|
||||
|
||||
function PART:Reset()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
self.pos = pos or Vector()
|
||||
self.vel = Vector()
|
||||
|
||||
self.ang = ang or Angle()
|
||||
self.angvel = Angle()
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self.pos = Vector()
|
||||
self.vel = Vector()
|
||||
|
||||
self.ang = Angle()
|
||||
self.angvel = Angle()
|
||||
|
||||
self.first_time_reset = true
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
if self.ResetOnHide then
|
||||
self:Reset()
|
||||
end
|
||||
end
|
||||
|
||||
local inf, ninf = math.huge, -math.huge
|
||||
|
||||
local function check_num(num)
|
||||
if num ~= inf and num ~= ninf and (num >= 0 or num <= 0) then
|
||||
return num
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
if self.first_time_reset then
|
||||
self:Reset()
|
||||
self.first_time_reset = false
|
||||
end
|
||||
|
||||
local delta = FrameTime()
|
||||
local speed = self.Speed * delta
|
||||
|
||||
self.vel = self.vel or VectorRand()
|
||||
self.pos = self.pos or pos * 1
|
||||
|
||||
if self.StopRadius ~= 0 and self.pos and self.pos:Distance(pos) < self.StopRadius then
|
||||
self.vel = Vector()
|
||||
return
|
||||
end
|
||||
|
||||
if self.JigglePosition then
|
||||
if not self.ConstrainX then
|
||||
self.vel.x = self.vel.x + (pos.x - self.pos.x)
|
||||
|
||||
if self.LocalVelocity then
|
||||
self.vel = self.vel + ang:Right() * self.ConstantVelocity.x
|
||||
else
|
||||
self.vel.x = self.vel.x + self.ConstantVelocity.x
|
||||
end
|
||||
|
||||
self.pos.x = self.pos.x + (self.vel.x * (self.Invert and -speed or speed))
|
||||
self.vel.x = self.vel.x * self.Strain
|
||||
else
|
||||
self.pos.x = pos.x
|
||||
end
|
||||
|
||||
if not self.ConstrainY then
|
||||
self.vel.y = self.vel.y + (pos.y - self.pos.y)
|
||||
|
||||
if self.LocalVelocity then
|
||||
self.vel = self.vel + ang:Forward() * self.ConstantVelocity.y
|
||||
else
|
||||
self.vel.y = self.vel.y + self.ConstantVelocity.y
|
||||
end
|
||||
|
||||
self.pos.y = self.pos.y + (self.vel.y * speed)
|
||||
self.vel.y = self.vel.y * self.Strain
|
||||
else
|
||||
self.pos.y = pos.y
|
||||
end
|
||||
|
||||
if not self.ConstrainZ then
|
||||
self.vel.z = self.vel.z + (pos.z - self.pos.z)
|
||||
|
||||
if self.LocalVelocity then
|
||||
self.vel = self.vel + ang:Up() * self.ConstantVelocity.z
|
||||
else
|
||||
self.vel.z = self.vel.z + self.ConstantVelocity.z
|
||||
end
|
||||
|
||||
self.pos.z = self.pos.z + (self.vel.z * speed)
|
||||
self.vel.z = self.vel.z * self.Strain
|
||||
else
|
||||
self.pos.z = pos.z
|
||||
end
|
||||
|
||||
if self.Ground then
|
||||
self.pos.z = util_QuickTrace(pos, physenv_GetGravity() * 100).HitPos.z
|
||||
end
|
||||
else
|
||||
self.pos = pos
|
||||
end
|
||||
|
||||
if self.ConstrainSphere > 0 then
|
||||
local len = math.min(self.pos:Distance(pos), self.ConstrainSphere)
|
||||
|
||||
self.pos = pos + (self.pos - pos):GetNormalized() * len
|
||||
end
|
||||
|
||||
if self.JiggleAngle then
|
||||
self.angvel = self.angvel or ang * 1
|
||||
self.ang = self.ang or ang * 1
|
||||
|
||||
if not self.ConstrainPitch then
|
||||
self.angvel.p = self.angvel.p + math_AngleDifference(ang.p, self.ang.p)
|
||||
self.ang.p = math_AngleDifference(self.ang.p, self.angvel.p * -speed)
|
||||
self.angvel.p = self.angvel.p * self.Strain
|
||||
end
|
||||
|
||||
if not self.ConstrainYaw then
|
||||
self.angvel.y = self.angvel.y + math_AngleDifference(ang.y, self.ang.y)
|
||||
self.ang.y = math_AngleDifference(self.ang.y, self.angvel.y * -speed)
|
||||
self.angvel.y = self.angvel.y * self.Strain
|
||||
end
|
||||
|
||||
if not self.ConstrainRoll then
|
||||
self.angvel.r = self.angvel.r + math_AngleDifference(ang.r, self.ang.r)
|
||||
self.ang.r = math_AngleDifference(self.ang.r, self.angvel.r * -speed)
|
||||
self.angvel.r = self.angvel.r * self.Strain
|
||||
end
|
||||
else
|
||||
self.ang = ang
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
self.pos.x = check_num(self.pos.x)
|
||||
self.pos.y = check_num(self.pos.y)
|
||||
self.pos.z = check_num(self.pos.z)
|
||||
|
||||
self.ang.p = check_num(self.ang.p)
|
||||
self.ang.y = check_num(self.ang.y)
|
||||
self.ang.r = check_num(self.ang.r)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
145
lua/pac3/core/client/parts/legacy/bodygroup.lua
Normal file
145
lua/pac3/core/client/parts/legacy/bodygroup.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
--[[
|
||||
| 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 = "bodygroup"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/user.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("BodyGroupName", "", {
|
||||
enums = function()
|
||||
return pace.current_part:GetBodyGroupNameList()
|
||||
end
|
||||
})
|
||||
BUILDER:GetSet("ModelIndex", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBodyGroupName(self:GetBodyGroupName())
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self.BodyGroupName ~= "" and self.BodyGroupName or "no bodygroup"
|
||||
end
|
||||
|
||||
function PART:SetBodyGroupName(str)
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() and not self.markedFailed and self.bodygroup_index and self.oldBodygroup then
|
||||
owner:SetBodygroup(self.bodygroup_index, self.oldBodygroup)
|
||||
|
||||
if owner:IsPlayer() then
|
||||
owner.pac_bodygroups_torender = owner.pac_bodygroups_torender or {}
|
||||
owner.pac_bodygroups_torender[self.bodygroup_index] = self.oldBodygroup
|
||||
end
|
||||
|
||||
self.oldBodygroup = nil
|
||||
end
|
||||
|
||||
self.BodyGroupName = str
|
||||
self.markedFailed = false
|
||||
self:UpdateBodygroupData()
|
||||
end
|
||||
|
||||
function PART:SetModelIndex(i)
|
||||
self.ModelIndex = math.floor(tonumber(i) or 0)
|
||||
self.markedFailed = false
|
||||
self:UpdateBodygroupData()
|
||||
end
|
||||
|
||||
function PART:UpdateBodygroupData()
|
||||
self.bodygroup_index = nil
|
||||
self.minIndex = 0
|
||||
self.maxIndex = 0
|
||||
self:SetError()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not IsValid(ent) or not ent:GetBodyGroups() then return end
|
||||
local fName = self.BodyGroupName:lower():Trim()
|
||||
|
||||
if fName == '' then
|
||||
return
|
||||
end
|
||||
|
||||
for i, info in ipairs(ent:GetBodyGroups()) do
|
||||
if info.name:lower():Trim() == fName then
|
||||
self.bodygroup_index = info.id
|
||||
self.maxIndex = info.num - 1
|
||||
self.markedFailed = false
|
||||
self.oldBodygroup = ent:GetBodygroup(info.id)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not self.markedFailed then
|
||||
pac.Message(self, ' - Unable to find bodygroup ' .. fName .. ' on ', ent)
|
||||
self:SetError("Unable to find bodygroup " .. fName .. " on " .. tostring(ent))
|
||||
self.markedFailed = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
if self.markedFailed then return end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
if not self.bodygroup_index then
|
||||
self:UpdateBodygroupData()
|
||||
return
|
||||
end
|
||||
|
||||
owner:SetBodygroup(self.bodygroup_index, self.ModelIndex)
|
||||
|
||||
if owner:IsPlayer() then
|
||||
owner.pac_bodygroups_torender = owner.pac_bodygroups_torender or {}
|
||||
owner.pac_bodygroups_torender[self.bodygroup_index] = self.ModelIndex
|
||||
end
|
||||
end
|
||||
|
||||
-- for the editor
|
||||
|
||||
function PART:GetModelIndexList()
|
||||
local out = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
for _, info in pairs(ent:GetBodyGroups()) do
|
||||
if info.id == self.bodygroup_info.id then
|
||||
for _, model in pairs(info.submodels) do
|
||||
table.insert(out, model)
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function PART:GetBodyGroupNameList()
|
||||
local out = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
for _, info in pairs(ent:GetBodyGroups()) do
|
||||
out[info.name] = info.name
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
297
lua/pac3/core/client/parts/legacy/bone.lua
Normal file
297
lua/pac3/core/client/parts/legacy/bone.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
--[[
|
||||
| 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 NULL = NULL
|
||||
local pairs = pairs
|
||||
|
||||
for _, v in pairs(ents.GetAll()) do
|
||||
v.pac_bone_setup_data = nil
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy bone"
|
||||
PART.ClassName = "bone"
|
||||
PART.Group = "legacy"
|
||||
PART.is_bone_part = true
|
||||
|
||||
PART.Icon = 'icon16/connect.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Jiggle", false)
|
||||
BUILDER:GetSet("ScaleChildren", false)
|
||||
BUILDER:GetSet("AlternativeBones", false)
|
||||
BUILDER:GetSet("MoveChildrenToOrigin", false)
|
||||
BUILDER:GetSet("FollowAnglesOnly", false)
|
||||
--BUILDER:GetSet("HideMesh", false)
|
||||
--BUILDER:GetSet("InvertHideMesh", false)
|
||||
BUILDER:GetSetPart("FollowPart")
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1), {editor_sensitivity = 0.25})
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Translucent")
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
local BaseClass_GetOwner = PART.GetOwner
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetBone()
|
||||
end
|
||||
|
||||
PART.ThinkTime = 0
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBone(self:GetBone())
|
||||
end
|
||||
PART.OnParent = PART.OnShow
|
||||
|
||||
function PART:OnThink()
|
||||
-- this is to setup the cached values
|
||||
if not self.first_getbpos and self:GetOwner():IsValid() then
|
||||
self:GetBonePosition()
|
||||
self.first_getbpos = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local owner = self:GetOwner()
|
||||
local pos, ang
|
||||
|
||||
pos, ang = pac.GetBonePosAng(owner, self.Bone, true)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local function manpos(ent, id, pos, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].pos = part.Position + part.PositionOffset
|
||||
else
|
||||
ent:ManipulateBonePosition(id, ent:GetManipulateBonePosition(id) + pos)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function manang(ent, id, ang, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].ang = part.Angles + part.AngleOffset
|
||||
else
|
||||
ent:ManipulateBoneAngles(id, ent:GetManipulateBoneAngles(id) + ang)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local inf_scale = Vector(math.huge, math.huge, math.huge)
|
||||
local inf_scale_tempcrashfix = Vector(1,1,1)*0.001
|
||||
|
||||
local function manscale(ent, id, scale, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].scale = scale
|
||||
else
|
||||
ent:ManipulateBoneScale(id, ent:GetManipulateBoneScale(id) * scale)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_children(owner, id, scale, origin, ownerScale)
|
||||
local count = owner:GetBoneCount()
|
||||
ownerScale = ownerScale or owner.pac3_Scale or 1
|
||||
|
||||
if count == 0 or count < id then return end
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if owner:GetBoneParent(i) ~= id then goto CONTINUE end
|
||||
|
||||
local mat = owner:GetBoneMatrix(i)
|
||||
|
||||
if mat then
|
||||
if origin then
|
||||
mat:SetTranslation(origin)
|
||||
end
|
||||
|
||||
mat:Scale(mat:GetScale() * scale / ownerScale)
|
||||
owner:SetBoneMatrix(i, mat)
|
||||
end
|
||||
|
||||
scale_children(owner, i, scale, origin, ownerScale)
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
local in_build = false
|
||||
function pac.build_bone_callback(ent)
|
||||
if in_build then return end
|
||||
|
||||
in_build = true
|
||||
if ent.pac_matrixhack then
|
||||
pac.LegacyScale(ent)
|
||||
end
|
||||
|
||||
if ent.pac_bone_setup_data then
|
||||
for uid, data in pairs(ent.pac_bone_setup_data) do
|
||||
local part = data.part or NULL
|
||||
|
||||
if part:IsValid() then
|
||||
local mat = ent:GetBoneMatrix(data.bone)
|
||||
if mat then
|
||||
if part.FollowPart:IsValid() and part.FollowPart.GetWorldAngles and part.FollowPart.GetWorldPosition then
|
||||
if part.FollowAnglesOnly then
|
||||
local pos = mat:GetTranslation()
|
||||
mat:SetAngles(part.Angles + part.AngleOffset + part.FollowPart:GetWorldAngles())
|
||||
mat:SetTranslation(pos)
|
||||
else
|
||||
mat:SetAngles(part.Angles + part.AngleOffset + part.FollowPart:GetWorldAngles())
|
||||
mat:SetTranslation(part.Position + part.PositionOffset + part.FollowPart:GetWorldPosition())
|
||||
end
|
||||
else
|
||||
if data.pos then
|
||||
mat:Translate(data.pos)
|
||||
end
|
||||
|
||||
if data.ang then
|
||||
mat:Rotate(data.ang)
|
||||
end
|
||||
end
|
||||
|
||||
if data.scale then
|
||||
mat:Scale(mat:GetScale() * data.scale)
|
||||
end
|
||||
|
||||
if part.ScaleChildren then
|
||||
local scale = part.Scale * part.Size
|
||||
scale_children(ent, data.bone, scale, data.origin)
|
||||
end
|
||||
|
||||
ent:SetBoneMatrix(data.bone, mat)
|
||||
end
|
||||
else
|
||||
ent.pac_bone_setup_data[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
in_build = false
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
local index = self:GetModelBoneIndex()
|
||||
|
||||
if not index then
|
||||
index = 0
|
||||
end
|
||||
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
|
||||
if self.AlternativeBones or self.ScaleChildren or self.FollowPart:IsValid() then
|
||||
owner.pac_bone_setup_data[self.UniqueID] = owner.pac_bone_setup_data[self.UniqueID] or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID].bone = index
|
||||
owner.pac_bone_setup_data[self.UniqueID].part = self
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
local ang = self:CalcAngles(self.Angles) or self.Angles
|
||||
|
||||
if not owner.pac_follow_bones_function then
|
||||
owner.pac_follow_bones_function = pac.build_bone_callback
|
||||
local id
|
||||
id = owner:AddCallback("BuildBonePositions", function(ent)
|
||||
if not self:IsValid() then
|
||||
owner:RemoveCallback("BuildBonePositions", id)
|
||||
return
|
||||
end
|
||||
pac.build_bone_callback(ent)
|
||||
end)
|
||||
end
|
||||
|
||||
if not self.FollowPart:IsValid() then
|
||||
if self.EyeAngles or self.AimPart:IsValid() then
|
||||
ang.r = ang.y
|
||||
ang.y = -ang.p
|
||||
end
|
||||
|
||||
manpos(owner, index, self.Position + self.PositionOffset, self)
|
||||
manang(owner, index, ang + self.AngleOffset, self)
|
||||
end
|
||||
|
||||
if owner.pac_bone_setup_data[self.UniqueID] then
|
||||
if self.MoveChildrenToOrigin then
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = self:GetBonePosition()
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = nil
|
||||
end
|
||||
end
|
||||
|
||||
owner:ManipulateBoneJiggle(index, isnumber(self.Jiggle) and self.Jiggle or (self.Jiggle and 1 or 0)) -- afaik anything but 1 is not doing anything at all
|
||||
|
||||
local scale
|
||||
|
||||
if self.HideMesh then
|
||||
scale = inf_scale
|
||||
|
||||
owner.pac_inf_scale = true
|
||||
|
||||
if self.InvertHideMesh then
|
||||
local count = owner:GetBoneCount()
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if i ~= index then
|
||||
manscale(owner, i, inf_scale, self)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
else
|
||||
|
||||
owner.pac_inf_scale = false
|
||||
|
||||
scale = self.Scale * self.Size
|
||||
end
|
||||
|
||||
manscale(owner, index, scale, self)
|
||||
|
||||
owner.needs_setupbones_from_legacy_bone_parts = true
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
297
lua/pac3/core/client/parts/legacy/bone2.lua
Normal file
297
lua/pac3/core/client/parts/legacy/bone2.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
--[[
|
||||
| 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 NULL = NULL
|
||||
local pairs = pairs
|
||||
|
||||
for _, v in pairs(ents.GetAll()) do
|
||||
v.pac_bone_setup_data = nil
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy experimental bone"
|
||||
PART.ClassName = "bone2"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/connect.png'
|
||||
PART.is_bone_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Jiggle", false)
|
||||
BUILDER:GetSet("ScaleChildren", false)
|
||||
BUILDER:GetSet("AlternativeBones", false)
|
||||
BUILDER:GetSet("MoveChildrenToOrigin", false)
|
||||
BUILDER:GetSet("FollowAnglesOnly", false)
|
||||
BUILDER:GetSet("HideMesh", false)
|
||||
BUILDER:GetSet("InvertHideMesh", false)
|
||||
BUILDER:GetSetPart("FollowPart")
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1), {editor_sensitivity = 0.25})
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Translucent")
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetBone()
|
||||
end
|
||||
|
||||
PART.ThinkTime = 0
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBone(self:GetBone())
|
||||
end
|
||||
|
||||
PART.OnParent = PART.OnShow
|
||||
|
||||
function PART:OnThink()
|
||||
-- this is to setup the cached values
|
||||
if not self.first_getbpos and self:GetOwner():IsValid() then
|
||||
self:GetBonePosition()
|
||||
self.first_getbpos = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local owner = self:GetOwner()
|
||||
return pac.GetBonePosAng(owner, self.Bone, true)
|
||||
end
|
||||
|
||||
local function manpos(ent, id, pos, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].pos = part.Position + part.PositionOffset
|
||||
else
|
||||
ent:ManipulateBonePosition(id, ent:GetManipulateBonePosition(id) + pos)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function manang(ent, id, ang, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].ang = part.Angles + part.AngleOffset
|
||||
else
|
||||
ent:ManipulateBoneAngles(id, ent:GetManipulateBoneAngles(id) + ang)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local inf_scale = Vector(math.huge, math.huge, math.huge)
|
||||
|
||||
local function manscale(ent, id, scale, part)
|
||||
if part and part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].scale = scale
|
||||
else
|
||||
ent:ManipulateBoneScale(id, ent:GetManipulateBoneScale(id) * scale)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_children(owner, id, scale, origin, ownerScale)
|
||||
local count = owner:GetBoneCount()
|
||||
ownerScale = ownerScale or owner.pac3_Scale or 1
|
||||
|
||||
if count == 0 or count < id then return end
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if owner:GetBoneParent(i) ~= id then goto CONTINUE end
|
||||
|
||||
local mat = owner:GetBoneMatrix(i)
|
||||
|
||||
if mat then
|
||||
if origin then
|
||||
mat:SetTranslation(origin)
|
||||
end
|
||||
|
||||
mat:Scale(mat:GetScale() * scale / ownerScale)
|
||||
owner:SetBoneMatrix(i, mat)
|
||||
end
|
||||
|
||||
scale_children(owner, i, scale, origin, ownerScale)
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function pac.build_bone_callback(ent)
|
||||
if ent.pac_matrixhack then
|
||||
pac.LegacyScale(ent)
|
||||
end
|
||||
|
||||
if ent.pac_bone_setup_data then
|
||||
for uid, data in pairs(ent.pac_bone_setup_data) do
|
||||
local part = data.part or NULL
|
||||
|
||||
if part:IsValid() then
|
||||
local mat = ent:GetBoneMatrix(data.bone)
|
||||
if mat then
|
||||
if part.FollowPart:IsValid() and part.FollowPart.GetWorldPosition then
|
||||
|
||||
mat:SetAngles(part.FollowPart:GetWorldAngles())
|
||||
|
||||
if not part.FollowAnglesOnly then
|
||||
mat:SetTranslation(part.FollowPart:GetWorldPosition())
|
||||
end
|
||||
|
||||
else
|
||||
if data.pos then
|
||||
mat:Translate(data.pos)
|
||||
end
|
||||
|
||||
if data.ang then
|
||||
mat:Rotate(data.ang)
|
||||
end
|
||||
end
|
||||
|
||||
if data.scale then
|
||||
mat:Scale(mat:GetScale() * data.scale)
|
||||
end
|
||||
|
||||
if part.ScaleChildren then
|
||||
local scale = part.Scale * part.Size
|
||||
scale_children(ent, data.bone, scale, data.origin)
|
||||
end
|
||||
|
||||
ent:SetBoneMatrix(data.bone, mat)
|
||||
end
|
||||
else
|
||||
ent.pac_bone_setup_data[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
local index = self:GetModelBoneIndex()
|
||||
|
||||
if not index then return end
|
||||
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
|
||||
if self.AlternativeBones or self.ScaleChildren or self.FollowPart:IsValid() then
|
||||
owner.pac_bone_setup_data[self.UniqueID] = owner.pac_bone_setup_data[self.UniqueID] or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID].bone = index
|
||||
owner.pac_bone_setup_data[self.UniqueID].part = self
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
local ang = self:CalcAngles(self.Angles) or self.Angles
|
||||
|
||||
if not owner.pac_follow_bones_function then
|
||||
owner.pac_follow_bones_function = pac.build_bone_callback
|
||||
local id
|
||||
id = owner:AddCallback("BuildBonePositions", function(ent)
|
||||
if pac and pac.build_bone_callback then
|
||||
pac.build_bone_callback(ent)
|
||||
else
|
||||
owner:RemoveCallback("BuildBonePositions", id)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if not self.FollowPart:IsValid() then
|
||||
if self.EyeAngles or self.AimPart:IsValid() then
|
||||
ang.r = ang.y
|
||||
ang.y = -ang.p
|
||||
end
|
||||
|
||||
local pos2, ang2 = self.Position + self.PositionOffset, ang + self.AngleOffset
|
||||
|
||||
local parent = self:GetParent()
|
||||
|
||||
if parent and parent:IsValid() and parent.ClassName == 'jiggle' then
|
||||
local pos3, ang3 = parent.Position, parent.Angles
|
||||
|
||||
if parent.pos then
|
||||
pos2 = pos2 + parent.pos - pos3
|
||||
end
|
||||
|
||||
if parent.ang then
|
||||
ang2 = ang2 + parent.ang - ang3
|
||||
end
|
||||
end
|
||||
|
||||
manpos(owner, index, pos2, self)
|
||||
manang(owner, index, ang2, self)
|
||||
end
|
||||
|
||||
if owner.pac_bone_setup_data[self.UniqueID] then
|
||||
if self.MoveChildrenToOrigin then
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = self:GetBonePosition()
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = nil
|
||||
end
|
||||
end
|
||||
|
||||
owner:ManipulateBoneJiggle(index, isnumber(self.Jiggle) and self.Jiggle or (self.Jiggle and 1 or 0)) -- afaik anything but 1 is not doing anything at all
|
||||
|
||||
local scale
|
||||
|
||||
if self.HideMesh then
|
||||
scale = inf_scale
|
||||
owner.pac_inf_scale = true
|
||||
|
||||
if self.InvertHideMesh then
|
||||
local count = owner:GetBoneCount()
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if i ~= index then
|
||||
manscale(owner, i, inf_scale, self)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
else
|
||||
owner.pac_inf_scale = false
|
||||
|
||||
scale = self.Scale * self.Size
|
||||
end
|
||||
|
||||
manscale(owner, index, scale, self)
|
||||
|
||||
owner.needs_setupbones_from_legacy_bone_parts = true
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
77
lua/pac3/core/client/parts/legacy/clip.lua
Normal file
77
lua/pac3/core/client/parts/legacy/clip.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
--[[
|
||||
| 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 render_EnableClipping = render.EnableClipping
|
||||
local render_PushCustomClipPlane = render.PushCustomClipPlane
|
||||
local LocalToWorld = LocalToWorld
|
||||
local IsEntity = IsEntity
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy clip"
|
||||
PART.ClassName = "clip"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/cut.png'
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
|
||||
function PART:OnParent(part)
|
||||
if not part.AddModifier then return end
|
||||
|
||||
part:AddModifier(self)
|
||||
|
||||
-- this is only really for halos..
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
function ent.pacDrawModel(ent)
|
||||
self:PreOnDraw()
|
||||
ent:DrawModel()
|
||||
self:PostOnDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
if not part:IsValid() then return end
|
||||
if not part.RemoveModifier then return end
|
||||
part:RemoveModifier(self)
|
||||
end
|
||||
|
||||
do
|
||||
local bclip
|
||||
|
||||
function PART:PreOnDraw()
|
||||
bclip = render_EnableClipping(true)
|
||||
|
||||
local pos, ang = LocalToWorld(self.Position + self.PositionOffset, self:CalcAngles(self.Angles + self.AngleOffset), self:GetBonePosition())
|
||||
local normal = ang:Forward()
|
||||
|
||||
render_PushCustomClipPlane(normal, normal:Dot(pos + normal))
|
||||
end
|
||||
|
||||
local render_PopCustomClipPlane = render.PopCustomClipPlane
|
||||
|
||||
function PART:PostOnDraw()
|
||||
render_PopCustomClipPlane()
|
||||
|
||||
render_EnableClipping(bclip)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
628
lua/pac3/core/client/parts/legacy/entity.lua
Normal file
628
lua/pac3/core/client/parts/legacy/entity.lua
Normal file
@@ -0,0 +1,628 @@
|
||||
--[[
|
||||
| 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 render_CullMode = render.CullMode
|
||||
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_MaterialOverride = render.MaterialOverride
|
||||
local game_SinglePlayer = game.SinglePlayer
|
||||
local Angle = Angle
|
||||
local Vector = Vector
|
||||
local NULL = NULL
|
||||
local Color = Color
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy entity"
|
||||
PART.ClassName = "entity"
|
||||
PART.Group = 'legacy'
|
||||
PART.Icon = 'icon16/brick.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:GetSet("Model", "")
|
||||
BUILDER:GetSet("Material", "")
|
||||
BUILDER:GetSet("HideEntity", false)
|
||||
BUILDER:GetSet("DrawWeapon", true)
|
||||
BUILDER:GetSet("MuteSounds", false)
|
||||
BUILDER:GetSet("AllowOggWhenMuted", false)
|
||||
BUILDER:GetSet("HideBullets", false)
|
||||
BUILDER:GetSet("DrawPlayerOnDeath", false)
|
||||
BUILDER:GetSet("HidePhysgunBeam", false)
|
||||
BUILDER:GetSet("UseLegacyScale", false)
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Fullbright", false)
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Invert", false)
|
||||
BUILDER:GetSet("DoubleFace", false)
|
||||
BUILDER:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.max(tonumber(num), 0)) end})
|
||||
BUILDER:GetSet("DrawShadow", true)
|
||||
BUILDER:GetSet("LodOverride", -1)
|
||||
BUILDER:SetPropertyGroup("movement")
|
||||
BUILDER:GetSet("SprintSpeed", 0)
|
||||
BUILDER:GetSet("RunSpeed", 0)
|
||||
BUILDER:GetSet("WalkSpeed", 0)
|
||||
BUILDER:GetSet("CrouchSpeed", 0)
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1))
|
||||
BUILDER:SetPropertyGroup("behavior")
|
||||
BUILDER:GetSet("RelativeBones", true)
|
||||
BUILDER:GetSet("Weapon", false)
|
||||
BUILDER:GetSet("InverseKinematics", false)
|
||||
BUILDER:GetSet("MuteFootsteps", false)
|
||||
BUILDER:GetSet("SuppressFrames", false)
|
||||
BUILDER:GetSet("AnimationRate", 1)
|
||||
BUILDER:GetSet("FallApartOnDeath", false)
|
||||
BUILDER:GetSet("DeathRagdollizeParent", false)
|
||||
BUILDER:GetSet("HideRagdollOnDeath", false)
|
||||
BUILDER:GetSetPart("EyeTarget")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local ent_fields = {}
|
||||
|
||||
function BUILDER:EntityField(name, field)
|
||||
|
||||
field = "pac_" .. field
|
||||
|
||||
ent_fields[field] = name
|
||||
|
||||
self.PART["Set" .. name] = function(self, val)
|
||||
self[name] = val
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner[field] = val
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
BUILDER:EntityField("InverseKinematics", "enable_ik")
|
||||
BUILDER:EntityField("MuteFootsteps", "mute_footsteps")
|
||||
BUILDER:EntityField("AnimationRate", "global_animation_rate")
|
||||
|
||||
BUILDER:EntityField("RunSpeed", "run_speed")
|
||||
BUILDER:EntityField("WalkSpeed", "walk_speed")
|
||||
BUILDER:EntityField("CrouchSpeed", "crouch_speed")
|
||||
BUILDER:EntityField("SprintSpeed", "sprint_speed")
|
||||
|
||||
BUILDER:EntityField("FallApartOnDeath", "death_physics_parts")
|
||||
BUILDER:EntityField("DeathRagdollizeParent", "death_ragdollize")
|
||||
BUILDER:EntityField("HideRagdollOnDeath", "death_hide_ragdoll")
|
||||
BUILDER:EntityField("DrawPlayerOnDeath", "draw_player_on_death")
|
||||
BUILDER:EntityField("HidePhysgunBeam", "hide_physgun_beam")
|
||||
|
||||
BUILDER:EntityField("MuteSounds", "mute_sounds")
|
||||
BUILDER:EntityField("AllowOggWhenMuted", "allow_ogg_sounds")
|
||||
BUILDER:EntityField("HideBullets", "hide_bullets")
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:IsPlayer() then
|
||||
return ent:Nick()
|
||||
else
|
||||
return language.GetPhrase(ent:GetClass())
|
||||
end
|
||||
end
|
||||
|
||||
if self.Weapon then
|
||||
return "Weapon"
|
||||
end
|
||||
|
||||
return self.ClassName
|
||||
end
|
||||
|
||||
|
||||
function PART:SetUseLegacyScale(b)
|
||||
self.UseLegacyScale = b
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetWeapon(b)
|
||||
self.Weapon = b
|
||||
if b then
|
||||
self:OnShow()
|
||||
else
|
||||
self:OnHide()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetDrawShadow(b)
|
||||
self.DrawShadow = b
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
ent:DrawShadow(b)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateScale(ent)
|
||||
ent = ent or self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if not self.UseLegacyScale then
|
||||
ent.pac3_Scale = self.Size
|
||||
end
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "size", ent, self.Size)
|
||||
end
|
||||
pac.SetModelScale(ent, self.Scale)
|
||||
else
|
||||
pac.SetModelScale(ent, self.Scale * self.Size)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSize(val)
|
||||
self.Size = val
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetScale(val)
|
||||
self.Scale = val
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetColor(var)
|
||||
var = var or Vector(255, 255, 255)
|
||||
|
||||
self.Color = var
|
||||
self.Colorf = Vector(var.r, var.g, var.b) / 255
|
||||
|
||||
self.Colorc = self.Colorc or Color(var.r, var.g, var.b, self.Alpha)
|
||||
self.Colorc.r = var.r
|
||||
self.Colorc.g = var.g
|
||||
self.Colorc.b = var.b
|
||||
end
|
||||
|
||||
function PART:SetAlpha(var)
|
||||
self.Alpha = var
|
||||
|
||||
self.Colorc = self.Colorc or Color(self.Color.r, self.Color.g, self.Color.b, self.Alpha)
|
||||
self.Colorc.a = var
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
end
|
||||
|
||||
function PART:SetRelativeBones(b)
|
||||
self.RelativeBones = b
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateWeaponDraw(ent)
|
||||
local wep = ent and ent:IsValid() and ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
||||
|
||||
if wep:IsWeapon() then
|
||||
if not wep.pac_weapon_class then
|
||||
wep:SetNoDraw(not self.DrawWeapon)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateColor()
|
||||
render_SetColorModulation(self.Colorf.r * self.Brightness, self.Colorf.g * self.Brightness, self.Colorf.b * self.Brightness)
|
||||
if pac.drawing_motionblur_alpha then return end
|
||||
render_SetBlend(self.Alpha)
|
||||
end
|
||||
|
||||
function PART:UpdateMaterial()
|
||||
local mat = self.MaterialOverride or self.Materialm
|
||||
if mat then
|
||||
render_MaterialOverride(mat)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateAll(ent)
|
||||
self:UpdateColor(ent)
|
||||
self:UpdateMaterial(ent)
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
|
||||
local angle_origin = Angle()
|
||||
|
||||
local function setup_suppress()
|
||||
local last_framenumber = 0
|
||||
local current_frame = 0
|
||||
local current_frame_count = 0
|
||||
|
||||
return function()
|
||||
local frame_number = FrameNumber()
|
||||
|
||||
if frame_number == last_framenumber then
|
||||
current_frame = current_frame + 1
|
||||
else
|
||||
last_framenumber = frame_number
|
||||
|
||||
if current_frame_count ~= current_frame then
|
||||
current_frame_count = current_frame
|
||||
end
|
||||
|
||||
current_frame = 1
|
||||
end
|
||||
|
||||
return current_frame < current_frame_count
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
self:SetModel(self:GetModel())
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
for _, field in pairs(ent_fields) do
|
||||
self["Set" .. field](self, self[field])
|
||||
end
|
||||
|
||||
self:SetColor(self:GetColor())
|
||||
ent:SetColor(self.Colorc)
|
||||
self:UpdateWeaponDraw(self:GetOwner())
|
||||
|
||||
function ent.RenderOverride()
|
||||
if self:IsValid() then
|
||||
if not self.HideEntity then
|
||||
if self.SuppressFrames then
|
||||
if not self.should_suppress then
|
||||
self.should_suppress = setup_suppress()
|
||||
end
|
||||
|
||||
if self.should_suppress() then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self:ModifiersPostEvent("PreDraw")
|
||||
self:PreEntityDraw(ent)
|
||||
|
||||
local modpos = not self.Position:IsZero() or not self.Angles:IsZero()
|
||||
local pos
|
||||
|
||||
self.BoneOverride = nil
|
||||
|
||||
if modpos then
|
||||
pos = ent:GetPos()
|
||||
|
||||
self.BoneOverride = "none"
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
ent:SetPos(pos)
|
||||
ent:SetRenderAngles(ang)
|
||||
pac.SetupBones(ent)
|
||||
end
|
||||
|
||||
ent:SetSkin(self.Skin)
|
||||
|
||||
if ent.pac_bodygroups_torender then
|
||||
for bgID, bgVal in pairs(ent.pac_bodygroups_torender) do
|
||||
ent:SetBodygroup(bgID, bgVal)
|
||||
end
|
||||
end
|
||||
|
||||
ent.pac_bodygroups_torender = nil
|
||||
|
||||
if self.EyeTarget.GetWorldPosition then
|
||||
ent:SetEyeTarget(self.EyeTarget:GetWorldPosition())
|
||||
end
|
||||
|
||||
ent:DrawModel()
|
||||
|
||||
if modpos then
|
||||
ent:SetPos(pos)
|
||||
ent:SetRenderAngles(angle_origin)
|
||||
end
|
||||
|
||||
self:PostEntityDraw(ent)
|
||||
self:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.current_ro = ent.RenderOverride
|
||||
|
||||
self:UpdateScale()
|
||||
|
||||
if self.LodOverride ~= -1 then self:SetLodOverride(self.LodOverride) end
|
||||
end
|
||||
|
||||
local ALLOW_TO_MDL = CreateConVar('pac_allow_mdl', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs')
|
||||
local ALLOW_TO_USE_MDL = CreateConVar('pac_allow_mdl_entity', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs as Entity')
|
||||
|
||||
function PART:SetModel(path)
|
||||
self.Model = path
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
pac.ResetBoneCache(ent)
|
||||
|
||||
if path:find("^http") then
|
||||
local status, reason = hook.Run('PAC3AllowMDLDownload', self:GetPlayerOwner(), self, path)
|
||||
local status2, reason2 = hook.Run('PAC3AllowEntityMDLDownload', self:GetPlayerOwner(), self, path)
|
||||
|
||||
if ALLOW_TO_USE_MDL:GetBool() and ALLOW_TO_MDL:GetBool() and status ~= false and status2 ~= false then
|
||||
if ent == pac.LocalPlayer then
|
||||
pac.Message("downloading ", path, " to use as player model")
|
||||
end
|
||||
|
||||
pac.DownloadMDL(path, function(real_path)
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.Message("finished downloading ", path)
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", ent, self.Model)
|
||||
end
|
||||
|
||||
ent:SetModel(real_path)
|
||||
|
||||
ent:SetSubMaterial()
|
||||
|
||||
for i = 0, #ent:GetBodyGroups() - 1 do
|
||||
ent:SetBodygroup(i, 0)
|
||||
end
|
||||
|
||||
pac.ResetBoneCache(ent)
|
||||
|
||||
for _, child in ipairs(self:GetChildrenList()) do
|
||||
child:OnShow(true)
|
||||
end
|
||||
end, function(err)
|
||||
pac.Message(err)
|
||||
self:SetError(err)
|
||||
end, self:GetPlayerOwner())
|
||||
|
||||
self.mdl_zip = true
|
||||
else
|
||||
local msg = reason2 or reason or "mdl is not allowed"
|
||||
self.loading = msg
|
||||
self:SetError(msg)
|
||||
pac.Message(self:GetPlayerOwner(), ' - mdl files are not allowed')
|
||||
end
|
||||
elseif self.Model ~= "" then
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", ent, self.Model)
|
||||
end
|
||||
|
||||
ent:SetModel(self.Model)
|
||||
|
||||
|
||||
pac.RunNextFrame('entity updatemat ' .. tostring(ent), function()
|
||||
if not ent:IsValid() or not self:IsValid() then return end
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetSubMaterial()
|
||||
|
||||
for i = 0, #ent:GetBodyGroups() - 1 do
|
||||
ent:SetBodygroup(i, 0)
|
||||
end
|
||||
|
||||
self:CallRecursive("CalcShowHide", true)
|
||||
end)
|
||||
|
||||
self.mdl_zip = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetLodOverride(num)
|
||||
self.LodOverride = num
|
||||
local owner = self:GetOwner()
|
||||
if owner:IsValid() then
|
||||
owner:SetLOD(num)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_mute_footsteps = self.MuteFootsteps
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
-- holy shit why does shooting reset the scale in singleplayer
|
||||
-- dumb workaround
|
||||
if game_SinglePlayer() and ent:IsPlayer() and ent:GetModelScale() ~= self.Size then
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
|
||||
if (self.HideEntity or self.Weapon) and self.current_ro ~= ent.RenderOverride then
|
||||
self:OnShow()
|
||||
end
|
||||
|
||||
ent.pac_material = self.Material
|
||||
ent.pac_materialm = self.Materialm
|
||||
ent.pac_color = self.Colorf
|
||||
ent.pac_alpha = self.Alpha
|
||||
ent.pac_brightness = self.Brightness
|
||||
|
||||
ent.pac_hide_entity = self.HideEntity
|
||||
ent.pac_fullbright = self.Fullbright
|
||||
ent.pac_invert = self.Invert
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.RestoreMutations(self:GetPlayerOwner(), "model", ent)
|
||||
pac.emut.RestoreMutations(self:GetPlayerOwner(), "size", ent)
|
||||
end
|
||||
|
||||
pac.SetModelScale(ent)
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
ent.RenderOverride = nil
|
||||
ent:SetColor(Color(255, 255, 255, 255))
|
||||
|
||||
ent.pac_material = nil
|
||||
ent.pac_materialm = nil
|
||||
ent.pac_color = nil
|
||||
ent.pac_alpha = nil
|
||||
ent.pac_brightness = nil
|
||||
|
||||
ent.pac_hide_entity = nil
|
||||
ent.pac_fullbright = nil
|
||||
ent.pac_invert = nil
|
||||
|
||||
for key in pairs(ent_fields) do
|
||||
ent[key] = nil
|
||||
end
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
-- do nothing, we want the player to feel small even on hide
|
||||
else
|
||||
pac.SetModelScale(ent, Vector(1,1,1))
|
||||
end
|
||||
|
||||
local weps = ent.GetWeapons and ent:GetWeapons()
|
||||
|
||||
if weps then
|
||||
for _, wep in pairs(weps) do
|
||||
if not wep.pac_weapon_class then
|
||||
wep:SetNoDraw(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.LodOverride ~= -1 then
|
||||
ent:SetLOD(-1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetHideEntity(b)
|
||||
self.HideEntity = b
|
||||
if b then
|
||||
self:OnHide()
|
||||
else
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PreEntityDraw(ent)
|
||||
self:UpdateWeaponDraw(ent)
|
||||
|
||||
self:UpdateColor(ent)
|
||||
self:UpdateMaterial(ent)
|
||||
|
||||
if self.Invert then
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(true)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PostEntityDraw()
|
||||
if self.Invert then
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(false)
|
||||
end
|
||||
|
||||
render_SetBlend(1)
|
||||
render_SetColorModulation(1,1,1)
|
||||
|
||||
render_MaterialOverride()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
|
||||
do
|
||||
local IN_SPEED = IN_SPEED
|
||||
local IN_WALK = IN_WALK
|
||||
local IN_DUCK = IN_DUCK
|
||||
|
||||
local function mod_speed(cmd, speed)
|
||||
if speed and speed ~= 0 then
|
||||
local forward = cmd:GetForwardMove()
|
||||
forward = forward > 0 and speed or forward < 0 and -speed or 0
|
||||
|
||||
local side = cmd:GetSideMove()
|
||||
side = side > 0 and speed or side < 0 and -speed or 0
|
||||
|
||||
|
||||
cmd:SetForwardMove(forward)
|
||||
cmd:SetSideMove(side)
|
||||
end
|
||||
end
|
||||
|
||||
pac.AddHook("CreateMove", "legacy_entity_part_speed_modifier", function(cmd)
|
||||
if cmd:KeyDown(IN_SPEED) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_sprint_speed)
|
||||
elseif cmd:KeyDown(IN_WALK) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_walk_speed)
|
||||
elseif cmd:KeyDown(IN_DUCK) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_crouch_speed)
|
||||
else
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_run_speed)
|
||||
end
|
||||
end)
|
||||
end
|
||||
63
lua/pac3/core/client/parts/legacy/light.lua
Normal file
63
lua/pac3/core/client/parts/legacy/light.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
--[[
|
||||
| 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_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy light"
|
||||
PART.ClassName = "light"
|
||||
PART.Group = "legacy"
|
||||
|
||||
PART.Icon = 'icon16/lightbulb.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Size", 5, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Style", 0, {editor_clamp = {0, 16}})
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local hue = pac.ColorToNames(self:GetColor())
|
||||
return hue .. " light"
|
||||
end
|
||||
|
||||
local DynamicLight = DynamicLight
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos = self:GetDrawPosition()
|
||||
local light = self.light or DynamicLight(tonumber(self.UniqueID))
|
||||
|
||||
light.Pos = pos
|
||||
|
||||
light.MinLight = self.Brightness
|
||||
light.Size = self.Size
|
||||
light.Style = self.Style
|
||||
|
||||
light.r = self.Color.r
|
||||
light.g = self.Color.g
|
||||
light.b = self.Color.b
|
||||
|
||||
-- 100000000 constant is better than calling pac.RealTime
|
||||
light.DieTime = 1000000000000 -- pac.RealTime
|
||||
|
||||
self.light = light
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local light = self.light
|
||||
if light then
|
||||
light.DieTime = 0
|
||||
light.Size = 0
|
||||
light.MinLight = 0
|
||||
light.Pos = Vector()
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
484
lua/pac3/core/client/parts/legacy/material.lua
Normal file
484
lua/pac3/core/client/parts/legacy/material.lua
Normal file
@@ -0,0 +1,484 @@
|
||||
--[[
|
||||
| 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.FriendlyName = "legacy material"
|
||||
PART.ClassName = "material"
|
||||
|
||||
PART.Icon = 'icon16/paintcan.png'
|
||||
PART.Group = "legacy"
|
||||
|
||||
local group_ordering = {
|
||||
{pattern = "phong", group = "phong"},
|
||||
{pattern = "envmap", group = "env map"},
|
||||
{pattern = {"ambientocclusion", "halflambert"}, group = "ambient occlusion"},
|
||||
{pattern = "detail", group = "detail"},
|
||||
{pattern = "rimlight", group = "rimlight"},
|
||||
{pattern = {"cloak", "refract"}, group = "cloak"},
|
||||
{pattern = "color", group = "colors"},
|
||||
{pattern = {"bumpmap", "basetexture", "^envmapmask$", "lightwarptexture"}, group = "textures"},
|
||||
{pattern = "flesh", group = "flesh"},
|
||||
{pattern = "selfillum", group = "selfillum"},
|
||||
{pattern = "emissive", group ="emissive"},
|
||||
}
|
||||
|
||||
PART.ShaderParams =
|
||||
{
|
||||
BaseTexture = "ITexture",
|
||||
|
||||
CloakPassEnabled = "boolean",
|
||||
CloakFactor = {type = "number", extra = {editor_sensitivity = 0.25, editor_clamp = {0, 1}}},
|
||||
CloakColorTint = "Vector",
|
||||
RefractAmount = "number",
|
||||
|
||||
BumpMap = "ITexture",
|
||||
LightWarpTexture = "ITexture",
|
||||
|
||||
Detail = "ITexture",
|
||||
DetailTint = "Vector",
|
||||
DetailScale = "number",
|
||||
DetailBlendMode = {type = "number", extra = {editor_onchange = function(pnl, num) return math.Round(math.max(num, 0)) end}},
|
||||
DetailBlendFactor = "number",
|
||||
|
||||
Phong = "boolean",
|
||||
PhongBoost = "number",
|
||||
PhongExponent = "number",
|
||||
PhongTint = "Vector",
|
||||
PhongFresnelRanges = {type = "Vector", extra = {editor_panel = "color"}},
|
||||
PhongWarpTexture = "ITexture",
|
||||
PhongAlbedoTint = "boolean",
|
||||
PhongExponentTexture = "ITexture",
|
||||
|
||||
Rimlight = "boolean",
|
||||
RimlightBoost = "number",
|
||||
RimlightExponent = "number",
|
||||
|
||||
-- doesn't do anything i think
|
||||
EnvMap = "ITexture",
|
||||
EnvMapMask = "ITexture",
|
||||
EnvMapTint = "Vector",
|
||||
EnvMapMode = "number",
|
||||
EnvMapContrast = "number",
|
||||
EnvMapMaskScale = "number",
|
||||
EnvMapSaturation = "Vector",
|
||||
NormalMapAlphaEnvMapMask = "boolean",
|
||||
BaseAlphaEnvMapMask = "boolean",
|
||||
Selfillum_EnvMapMask_Alpha = "number",
|
||||
|
||||
AmbientOcclusion = "boolean",
|
||||
AmbientOcclusionColor = "Vector",
|
||||
AmbientOcclusionTexture = "ITexture",
|
||||
|
||||
BlendTintByBaseAlpha = "boolean",
|
||||
BlendTintColorOverBase = "Vector",
|
||||
ColorTint_Base = "Vector",
|
||||
ColorTint_Tmp = "Vector",
|
||||
Color = "Vector",
|
||||
Color2 = "Vector",
|
||||
Additive = "boolean",
|
||||
AlphaTest = "boolean",
|
||||
TranslucentX = "boolean",
|
||||
|
||||
|
||||
HalfLambert = "boolean",
|
||||
|
||||
Selfillum = "boolean",
|
||||
SelfillumTint = "Vector",
|
||||
SelfillumMask = "ITexture",
|
||||
Selfillum_Envmapmask_Alpha = "ITexture",
|
||||
SelfillumFresnel = "boolean",
|
||||
SelfillumFresnlenMinMaxExp = "Vector",
|
||||
|
||||
FleshInteriorEnabled = "boolean", --"0", "Enable Flesh interior blend pass" )
|
||||
FleshInteriorTexture = "ITexture", --"", "Flesh color texture" )
|
||||
FleshInteriorNoiseTexture = "ITexture", --"", "Flesh noise texture" )
|
||||
FleshBorderTexture1D = "ITexture", --"", "Flesh border 1D texture" )
|
||||
FleshNormalTexture = "ITexture", --"", "Flesh normal texture" )
|
||||
FleshSubsurfaceTexture = "ITexture", --"", "Flesh subsurface texture" )
|
||||
FleshCubeTexture = "ITexture", --"", "Flesh cubemap texture" )
|
||||
FleshBorderNoiseScale = "number", --"1.5", "Flesh Noise UV scalar for border" )
|
||||
FleshDebugForceFleshOn = "boolean", --"0", "Flesh Debug full flesh" )
|
||||
|
||||
--FleshEFFECTCENTERRADIUS1, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS2, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS3, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS4, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
|
||||
FleshSubsurfaceTint = "Vector", --"[1 1 1]", "Subsurface Color" )
|
||||
FleshBorderWidth = "number", --"0.3", "Flesh border" )
|
||||
FleshBorderSoftness = "number", --"0.42", "Flesh border softness (> 0.0 && <= 0.5)" )
|
||||
FleshBorderTint = "Vector", --"[1 1 1]", "Flesh border Color" )
|
||||
FleshGlobalOpacity = "number", --"1.0", "Flesh global opacity" )
|
||||
FleshGlossBrightness = "number", --"0.66", "Flesh gloss brightness" )
|
||||
FleshScrollSpeed = "number", --"1.0", "Flesh scroll speed" )
|
||||
|
||||
EmissiveBlendEnabled = "boolean",
|
||||
EmissiveBlendTexture = "ITexture",
|
||||
EmissiveBlendBaseTexture = "ITexture",
|
||||
EmissiveBlendFlowTexture = "ITexture",
|
||||
EmissiveBlendTint = "Vector",
|
||||
EmissiveBlendScrollVector = "Vector",
|
||||
|
||||
DistanceAlpha = "number",
|
||||
VertexAlpha = "boolean",
|
||||
Alpha = "number",
|
||||
}
|
||||
|
||||
function PART:OnThink()
|
||||
if self.delay_set and self.Parent then
|
||||
self.delay_set()
|
||||
self.delay_set = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function setup(PART)
|
||||
local sorted = {}
|
||||
for k,v in pairs(PART.ShaderParams) do
|
||||
table.insert(sorted, {k = k, v = v})
|
||||
end
|
||||
table.sort(sorted, function(a, b) return a.k > b.k end)
|
||||
|
||||
for pass = 1, 2 do
|
||||
for _, info in ipairs(group_ordering) do
|
||||
for _, v in ipairs(sorted) do
|
||||
local name, T = v.k, v.v
|
||||
|
||||
local found
|
||||
|
||||
if istable(info.pattern) then
|
||||
for k,v in pairs(info.pattern) do
|
||||
if name:lower():find(v) then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
found = name:lower():find(info.pattern)
|
||||
end
|
||||
|
||||
if pass == 1 then
|
||||
if found then
|
||||
BUILDER:SetPropertyGroup(info.group)
|
||||
else
|
||||
goto CONTINUE
|
||||
end
|
||||
elseif pass == 2 then
|
||||
if not found then
|
||||
BUILDER:SetPropertyGroup()
|
||||
else
|
||||
goto CONTINUE
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local extra
|
||||
if istable(T) then
|
||||
extra = T.extra
|
||||
T = T.type
|
||||
end
|
||||
if T == "ITexture" then
|
||||
BUILDER:GetSet(name, "", {editor_panel = "textures"})
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
if
|
||||
self.SKIP or
|
||||
pac.Handleurltex(
|
||||
self,
|
||||
var,
|
||||
function(_, tex)
|
||||
local mat = self:GetMaterialFromParent()
|
||||
if mat then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
|
||||
self.SKIP = true
|
||||
self:UpdateMaterial()
|
||||
self.SKIP = false
|
||||
else
|
||||
self.delay_set = function()
|
||||
local mat = self:GetMaterialFromParent()
|
||||
if mat then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
self.SKIP = true
|
||||
self:UpdateMaterial()
|
||||
self.SKIP = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if var ~= "" then
|
||||
local _mat = Material(var)
|
||||
local tex = _mat:GetTexture("$" .. name)
|
||||
|
||||
if not tex or tex:GetName() == "error" then
|
||||
tex = pac.CreateMaterial("pac3_tex_" .. var .. "_" .. self.Id, "VertexLitGeneric", {["$basetexture"] = var}):GetTexture("$basetexture")
|
||||
|
||||
if not tex or tex:GetName() == "error" then
|
||||
tex = _mat:GetTexture("$basetexture")
|
||||
end
|
||||
end
|
||||
|
||||
if tex then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
end
|
||||
else
|
||||
mat:SetUndefined("$" .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif T == "boolean" then
|
||||
BUILDER:GetSet(name, false)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if name == "TranslucentX" then
|
||||
name = "Translucent"
|
||||
end
|
||||
|
||||
mat:SetInt("$" .. name, var and 1 or 0) -- setint crashes?
|
||||
end
|
||||
end
|
||||
elseif T == "number" then
|
||||
BUILDER:GetSet(name, 0)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
mat:SetFloat("$" .. name, var)
|
||||
end
|
||||
end
|
||||
elseif T == "Vector" then
|
||||
local def = Vector(0,0,0)
|
||||
|
||||
-- hack
|
||||
local key = name:lower()
|
||||
if key == "color" or key == "color2" then
|
||||
def = Vector(1,1,1)
|
||||
end
|
||||
|
||||
BUILDER:GetSet(name, def)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if key == "color" or key == "color2" then
|
||||
timer.Simple(0.1, function() mat:SetVector("$" .. name, var) end)
|
||||
end
|
||||
|
||||
mat:SetVector("$" .. name, var)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function add_transform(texture_name)
|
||||
local position_key = texture_name.."Position"
|
||||
local scale_key = texture_name.."Scale"
|
||||
local angle_key = texture_name.."Angle"
|
||||
local angle_center_key = texture_name.."AngleCenter"
|
||||
|
||||
BUILDER:GetSet(position_key, Vector(0, 0, 0))
|
||||
BUILDER:GetSet(scale_key, Vector(1, 1, 1))
|
||||
BUILDER:GetSet(angle_key, 0, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet(angle_center_key, Vector(0.5, 0.5, 0))
|
||||
|
||||
PART.TransformVars = PART.TransformVars or {}
|
||||
PART.TransformVars[position_key] = true
|
||||
PART.TransformVars[scale_key] = true
|
||||
PART.TransformVars[angle_key] = true
|
||||
PART.TransformVars[angle_center_key] = true
|
||||
|
||||
local shader_key = "$"..texture_name.."transform"
|
||||
|
||||
local function setup_matrix(self)
|
||||
self.matrix = self.matrix or Matrix()
|
||||
self.translation_vector = self.translation_vector or Vector(0, 0, 0)
|
||||
self.rotation_angle = self.rotation_angle or Angle(0, 0, 0)
|
||||
|
||||
self.matrix:Identity()
|
||||
self.matrix:Translate(self.translation_vector)
|
||||
|
||||
self.matrix:Translate(self[angle_center_key])
|
||||
self.matrix:Rotate(self.rotation_angle)
|
||||
self.matrix:Translate(-self[angle_center_key])
|
||||
|
||||
self.matrix:SetScale(self[scale_key])
|
||||
end
|
||||
|
||||
PART["Set" .. position_key] = function(self, vec)
|
||||
self[position_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self.translation_vector.x = self[position_key].x%1
|
||||
self.translation_vector.y = self[position_key].y%1
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. scale_key] = function(self, vec)
|
||||
self[scale_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_key] = function(self, num)
|
||||
self[angle_key] = num
|
||||
setup_matrix(self)
|
||||
|
||||
self.rotation_angle.y = self[angle_key]*360
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_center_key] = function(self, vec)
|
||||
self[angle_center_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
setup(PART)
|
||||
add_transform("BaseTexture")
|
||||
--add_transform("Bump") -- doesn't work
|
||||
--add_transform("EnvMapMask")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetMaterialFromParent()
|
||||
if self:GetParent():IsValid() then
|
||||
if not self.Materialm then
|
||||
local mat = pac.CreateMaterial(pac.uid"pac_material_", "VertexLitGeneric", {})
|
||||
|
||||
if self.Parent.Materialm then
|
||||
local tex
|
||||
tex = self.Parent.Materialm:GetTexture("$bumpmap")
|
||||
if tex and not tex:IsError() then
|
||||
mat:SetTexture("$bumpmap", tex)
|
||||
end
|
||||
|
||||
local tex = self.Parent.Materialm:GetTexture("$basetexture")
|
||||
if tex and not tex:IsError() then
|
||||
mat:SetTexture("$basetexture", tex)
|
||||
end
|
||||
end
|
||||
|
||||
self.Materialm = mat
|
||||
end
|
||||
|
||||
self.Parent.Materialm = self.Materialm
|
||||
|
||||
if self.Parent.UpdateSubMaterialId then
|
||||
self.Parent:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
return self.Materialm
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetTranslucent(b)
|
||||
self.Translucent = b
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:GetRawMaterial()
|
||||
if not self.Materialm then
|
||||
local mat = pac.CreateMaterial(pac.uid"pac_material_", "VertexLitGeneric", {})
|
||||
self.Materialm = mat
|
||||
end
|
||||
|
||||
return self.Materialm
|
||||
end
|
||||
|
||||
function PART:OnParent(parent)
|
||||
self:GetMaterialFromParent()
|
||||
end
|
||||
|
||||
function PART:UpdateMaterial(now)
|
||||
if not self:GetPlayerOwner():IsValid() then return end
|
||||
self:GetMaterialFromParent()
|
||||
|
||||
for key, val in pairs(self.StorableVars) do
|
||||
if self.ShaderParams[key] or self.TransformVars[key] then
|
||||
self["Set" .. key](self, self["Get"..key](self))
|
||||
end
|
||||
end
|
||||
|
||||
pac.UpdateMaterialParts("update", self:GetPlayerOwnerId(), self, self.Materialm)
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if self:GetPlayerOwner():IsValid() then
|
||||
pac.UpdateMaterialParts("remove", self:GetPlayerOwnerId(), self, self.Materialm)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnMaterialChanged()
|
||||
if self.suppress_event then return end
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:OnParent(parent)
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:OnUnParent(parent)
|
||||
self.Materialm = nil
|
||||
self.updated = false
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local parent = self:GetParent()
|
||||
|
||||
if parent:IsValid() and parent.SetMaterial then
|
||||
self.suppress_event = true
|
||||
parent:SetMaterial(parent.Material)
|
||||
self.suppress_event = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self:UpdateMaterial()
|
||||
|
||||
local name = self.Name
|
||||
|
||||
pac.UpdateMaterialParts("show", self:GetPlayerOwnerId(), self, self.Name)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
900
lua/pac3/core/client/parts/legacy/model.lua
Normal file
900
lua/pac3/core/client/parts/legacy/model.lua
Normal file
@@ -0,0 +1,900 @@
|
||||
--[[
|
||||
| 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 pac = pac
|
||||
|
||||
local math_max = math.max
|
||||
local math_min = math.min
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
|
||||
local Matrix = Matrix
|
||||
local Vector = Vector
|
||||
|
||||
local cam_PushModelMatrix = cam.PushModelMatrix
|
||||
local cam_PopModelMatrix = cam.PopModelMatrix
|
||||
|
||||
local render = render
|
||||
local render_CullMode = render.CullMode
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_SetMaterial = render.SetMaterial
|
||||
local render_ModelMaterialOverride = render.MaterialOverride
|
||||
local render_MaterialOverride = render.ModelMaterialOverride
|
||||
local render_PopFilterMag = render.PopFilterMag
|
||||
local render_PopFilterMin = render.PopFilterMin
|
||||
local render_PopFlashlightMode = render.PopFlashlightMode
|
||||
local render_PushFilterMag = render.PushFilterMag
|
||||
local render_PushFilterMin = render.PushFilterMin
|
||||
local render_PushFlashlightMode = render.PushFlashlightMode
|
||||
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
||||
|
||||
local IMaterial_GetFloat = FindMetaTable("IMaterial").GetFloat
|
||||
local IMaterial_GetVector = FindMetaTable("IMaterial").GetVector
|
||||
local IMaterial_SetFloat = FindMetaTable("IMaterial").SetFloat
|
||||
local IMaterial_SetVector = FindMetaTable("IMaterial").SetVector
|
||||
|
||||
local EF_BONEMERGE = EF_BONEMERGE
|
||||
|
||||
local MATERIAL_CULLMODE_CW = MATERIAL_CULLMODE_CW
|
||||
local MATERIAL_CULLMODE_CCW = MATERIAL_CULLMODE_CCW
|
||||
|
||||
local TEXFILTER = TEXFILTER
|
||||
local NULL = NULL
|
||||
local Color = Color
|
||||
|
||||
pac.DisableColoring = false
|
||||
pac.DisableDoubleFace = false
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy model"
|
||||
PART.ClassName = "model"
|
||||
PART.Category = "model"
|
||||
PART.ManualDraw = true
|
||||
PART.HandleModifiersManually = true
|
||||
PART.Icon = 'icon16/shape_square.png'
|
||||
PART.Group = "legacy"
|
||||
PART.ThinkTime = 0.5
|
||||
|
||||
PART.is_model_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Model", "models/dav0r/hoverball.mdl", {editor_panel = "model"})
|
||||
BUILDER:GetSet("Material", "", {editor_panel = "material"})
|
||||
BUILDER:GetSet("UseLegacyScale", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:GetSet("BoneMerge", false)
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1))
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
BUILDER:GetSet("AlternativeScaling", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Fullbright", false)
|
||||
BUILDER:GetSet("CellShade", 0, {editor_sensitivity = 0.1})
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Invert", false)
|
||||
BUILDER:GetSet("DoubleFace", false)
|
||||
BUILDER:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.max(tonumber(num), 0)) end})
|
||||
BUILDER:GetSet("LodOverride", -1)
|
||||
BUILDER:GetSet("Passes", 1)
|
||||
BUILDER:GetSet("TintColor", Vector(0, 0, 0), {editor_panel = "color"})
|
||||
BUILDER:GetSet("LightBlend", 1)
|
||||
BUILDER:GetSet("ModelFallback", "", {editor_panel = "model"})
|
||||
BUILDER:GetSet("TextureFilter", 3)
|
||||
BUILDER:GetSet("BlurLength", 0)
|
||||
BUILDER:GetSet("BlurSpacing", 0)
|
||||
BUILDER:GetSet("UsePlayerColor", false)
|
||||
BUILDER:GetSet("UseWeaponColor", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:GetSet("OwnerEntity", false)
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName(("/" .. self:GetModel()):match(".+/(.-)%."))
|
||||
|
||||
return str and str:gsub("%d", "") or "error"
|
||||
end
|
||||
|
||||
function PART:Reset()
|
||||
self:Initialize(self.is_obj)
|
||||
for _, key in pairs(self:GetStorableVars()) do
|
||||
if PART[key] then
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetUseLegacyScale(b)
|
||||
self.UseLegacyScale = b
|
||||
if not b then
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetTextureFilter(num)
|
||||
self.TextureFilter = num
|
||||
|
||||
self.texfilter_enum = math.Clamp(math.Round(num), 0, 3)
|
||||
end
|
||||
|
||||
function PART:Initialize(is_obj)
|
||||
self.Owner = pac.CreateEntity(self:GetModel(), is_obj)
|
||||
if not self.Owner:IsValid() then
|
||||
pac.Message("pac3 failed to create entity!")
|
||||
return
|
||||
end
|
||||
self.Owner:SetNoDraw(true)
|
||||
self.Owner.PACPart = self
|
||||
self.is_obj = is_obj
|
||||
end
|
||||
|
||||
|
||||
function PART:OnBecomePhysics()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
ent:PhysicsInit(SOLID_NONE)
|
||||
ent:SetMoveType(MOVETYPE_NONE)
|
||||
ent:SetNoDraw(true)
|
||||
ent.RenderOverride = nil
|
||||
|
||||
self.skip_orient = false
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local owner = self:GetParentOwner()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and owner:IsValid() and owner ~= ent then
|
||||
ent:SetPos(owner:EyePos())
|
||||
|
||||
if self.OwnerEntity then
|
||||
self:SetOwnerEntity(self.OwnerEntity)
|
||||
end
|
||||
end
|
||||
|
||||
if self.BlurLength > 0 then
|
||||
self.blur_history = {}
|
||||
self.blur_last_add = 0
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
function PART:OnThink()
|
||||
pac.SetModelScale(self:GetOwner(), self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
|
||||
self:CheckScale()
|
||||
self:CheckBoneMerge()
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
ent.pac_matproxies = ent.pac_matproxies or {}
|
||||
ent.pac_matproxies.ItemTintColor = self.TintColor / 255
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local NULL = NULL
|
||||
|
||||
local function BIND_MATPROXY(NAME, TYPE)
|
||||
|
||||
local set = "Set" .. TYPE
|
||||
|
||||
matproxy.Add(
|
||||
{
|
||||
name = NAME,
|
||||
|
||||
init = function(self, mat, values)
|
||||
self.result = values.resultvar
|
||||
end,
|
||||
|
||||
bind = function(self, mat, ent)
|
||||
ent = ent or NULL
|
||||
if ent:IsValid() then
|
||||
if ent.pac_matproxies and ent.pac_matproxies[NAME] then
|
||||
mat[set](mat, self.result, ent.pac_matproxies[NAME])
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
-- tf2
|
||||
BIND_MATPROXY("ItemTintColor", "Vector")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetOwnerEntity(b)
|
||||
local ent = self:GetParentOwner()
|
||||
if ent:IsValid() then
|
||||
if b then
|
||||
self.Owner = ent
|
||||
|
||||
function ent.RenderOverride()
|
||||
if self:IsValid() then
|
||||
if not self.HideEntity then
|
||||
self:PreEntityDraw(ent, ent:GetPos(), ent:GetAngles())
|
||||
ent:DrawModel()
|
||||
self:PostEntityDraw(ent, ent:GetPos(), ent:GetAngles())
|
||||
end
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
elseif self.OwnerEntity then
|
||||
self.Owner = NULL
|
||||
|
||||
ent.RenderOverride = nil
|
||||
pac.SetModelScale(ent, Vector(1,1,1), nil, self.UseLegacyScale)
|
||||
|
||||
self:Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
self.OwnerEntity = b
|
||||
end
|
||||
|
||||
function PART:PreEntityDraw(ent, pos, ang)
|
||||
if not ent:IsPlayer() and pos and ang then
|
||||
if not self.skip_orient then
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
self:ModifiersPreEvent("OnDraw")
|
||||
|
||||
if not pac.DisableDoubleFace and (self.DoubleFace or self.Invert) then
|
||||
render_CullMode(MATERIAL_CULLMODE_CW)
|
||||
end
|
||||
|
||||
if not pac.DisableColoring then
|
||||
if not self.Colorf then
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
if self.UseWeaponColor or self.UsePlayerColor then
|
||||
local ply = self:GetPlayerOwner()
|
||||
if ply:IsValid() then
|
||||
local c
|
||||
|
||||
c = ply:GetPlayerColor()
|
||||
if c ~= self.last_playercolor then
|
||||
self:SetColor(self:GetColor())
|
||||
self.last_playercolor = c
|
||||
end
|
||||
|
||||
c = ply:GetWeaponColor()
|
||||
if c ~= self.last_weaponcolor then
|
||||
self:SetColor(self:GetColor())
|
||||
self.last_weaponcolor = c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save existing material color and alpha
|
||||
if self.Materialm then
|
||||
-- this is so bad for GC performance
|
||||
self.OriginalMaterialColor = self.OriginalMaterialColor or IMaterial_GetVector (self.Materialm, "$color")
|
||||
self.OriginalMaterialAlpha = self.OriginalMaterialAlpha or IMaterial_GetFloat (self.Materialm, "$alpha")
|
||||
end
|
||||
|
||||
local r, g, b = self.Colorf[1], self.Colorf[2], self.Colorf[3]
|
||||
|
||||
if self.LightBlend ~= 1 then
|
||||
local v = render.GetLightColor(pos)
|
||||
r = r * v.r * self.LightBlend
|
||||
g = g * v.g * self.LightBlend
|
||||
b = b * v.b * self.LightBlend
|
||||
|
||||
v = render.GetAmbientLightColor(pos)
|
||||
r = r * v.r * self.LightBlend
|
||||
g = g * v.g * self.LightBlend
|
||||
b = b * v.b * self.LightBlend
|
||||
end
|
||||
|
||||
-- render.SetColorModulation and render.SetAlpha set the material $color and $alpha.
|
||||
render_SetColorModulation(r,g,b)
|
||||
render_SetBlend(self.Alpha)
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local DEFAULT_COLOR = Vector(1, 1, 1)
|
||||
local WHITE = Material("models/debug/debugwhite")
|
||||
|
||||
function PART:PostEntityDraw(ent, pos, ang)
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
if not pac.DisableDoubleFace then
|
||||
if self.DoubleFace then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
elseif self.Invert then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(false)
|
||||
end
|
||||
|
||||
if self.CellShade > 0 then
|
||||
self:CheckScale()
|
||||
self:CheckBoneMerge()
|
||||
|
||||
pac.SetModelScale(ent, self.Scale * self.Size * (1 + self.CellShade), nil, self.UseLegacyScale)
|
||||
render_CullMode(MATERIAL_CULLMODE_CW)
|
||||
render_SetColorModulation(0,0,0)
|
||||
render_SuppressEngineLighting(true)
|
||||
render_MaterialOverride(WHITE)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
render_MaterialOverride()
|
||||
render_SuppressEngineLighting(false)
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
pac.SetModelScale(ent, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
|
||||
-- Restore material color and alpha
|
||||
if self.Materialm then
|
||||
IMaterial_SetVector (self.Materialm, "$color", self.OriginalMaterialColor or DEFAULT_COLOR)
|
||||
IMaterial_SetFloat (self.Materialm, "$alpha", self.OriginalMaterialAlpha or 1)
|
||||
self.OriginalMaterialColor = nil
|
||||
self.OriginalMaterialAlpha = nil
|
||||
end
|
||||
|
||||
self:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then
|
||||
self:Reset()
|
||||
ent = self:GetOwner()
|
||||
if not ent:IsValid() then
|
||||
pac.Message("WTF", ent, self:GetOwner())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
self:PreEntityDraw(ent, pos, ang)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
self:PostEntityDraw(ent, pos, ang)
|
||||
|
||||
pac.SetupBones(ent)
|
||||
pac.ResetBones(ent)
|
||||
|
||||
if ent.pac_can_legacy_scale ~= false then
|
||||
ent.pac_can_legacy_scale = not not ent.pac_can_legacy_scale
|
||||
end
|
||||
end
|
||||
|
||||
surface.CreateFont("pac_urlobj_loading",
|
||||
{
|
||||
font = "Arial",
|
||||
size = 20,
|
||||
weight = 10,
|
||||
antialias = true,
|
||||
outline = true,
|
||||
}
|
||||
)
|
||||
|
||||
-- ugh lol
|
||||
local function RealDrawModel(self, ent, pos, ang)
|
||||
if self.Mesh then
|
||||
ent:SetModelScale(0,0)
|
||||
ent:DrawModel()
|
||||
|
||||
local matrix = Matrix()
|
||||
|
||||
matrix:SetAngles(ang)
|
||||
matrix:SetTranslation(pos)
|
||||
|
||||
if ent.pac_model_scale then
|
||||
matrix:Scale(ent.pac_model_scale)
|
||||
else
|
||||
matrix:Scale(self.Scale * self.Size)
|
||||
end
|
||||
|
||||
cam_PushModelMatrix(matrix)
|
||||
self.Mesh:Draw()
|
||||
cam_PopModelMatrix()
|
||||
else
|
||||
ent:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local _self, _ent, _pos, _ang
|
||||
local _return_status = false
|
||||
|
||||
local function protected_real_draw_model()
|
||||
RealDrawModel(_self, _ent, _pos, _ang)
|
||||
end
|
||||
|
||||
local function protected_inner_draw_model()
|
||||
local mat = _self.MaterialOverride or _self.Materialm
|
||||
|
||||
render_MaterialOverride(mat)
|
||||
|
||||
if mat then
|
||||
render_SetMaterial(mat)
|
||||
end
|
||||
|
||||
pac.render_material = mat
|
||||
|
||||
-- Render model
|
||||
local passCount = math_max (1, _self.Passes)
|
||||
|
||||
if _self.Alpha >= 1 then
|
||||
passCount = math_min (passCount, 1)
|
||||
end
|
||||
|
||||
for _ = 1, passCount do
|
||||
local status = ProtectedCall(protected_real_draw_model)
|
||||
|
||||
if not status then
|
||||
_return_status = false
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
render_PushFlashlightMode(true)
|
||||
|
||||
ProtectedCall(protected_real_draw_model)
|
||||
|
||||
render_PopFlashlightMode()
|
||||
|
||||
_return_status = true
|
||||
end
|
||||
|
||||
function PART:DrawModel(ent, pos, ang)
|
||||
if self.Alpha == 0 or self.Size == 0 then return end
|
||||
|
||||
if self.loading_obj then
|
||||
self:DrawLoadingText(ent, pos, ang)
|
||||
end
|
||||
|
||||
if self.loading_obj and not self.Mesh then return end
|
||||
|
||||
local textureFilter = self.texfilter_enum or TEXFILTER.ANISOTROPIC
|
||||
local filter_updated = textureFilter ~= TEXFILTER.ANISOTROPIC or self.Mesh
|
||||
|
||||
if filter_updated then
|
||||
render_PushFilterMin(textureFilter)
|
||||
render_PushFilterMag(textureFilter)
|
||||
end
|
||||
|
||||
_self, _ent, _pos, _ang = self, ent, pos, ang
|
||||
|
||||
ProtectedCall(protected_inner_draw_model)
|
||||
|
||||
if filter_updated then
|
||||
render_PopFilterMag()
|
||||
render_PopFilterMin()
|
||||
end
|
||||
|
||||
-- Render "blur"
|
||||
if self.BlurLength > 0 and _return_status then
|
||||
self:DrawBlur(ent, pos, ang)
|
||||
end
|
||||
|
||||
render_MaterialOverride()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:DrawLoadingText(ent, pos, ang)
|
||||
cam.Start2D()
|
||||
cam.IgnoreZ(true)
|
||||
local pos2d = pos:ToScreen()
|
||||
|
||||
surface.SetFont("pac_urlobj_loading")
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
|
||||
local str = self.loading_obj .. string.rep(".", pac.RealTime * 3 % 3)
|
||||
local w, h = surface.GetTextSize(self.loading_obj .. "...")
|
||||
|
||||
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
||||
surface.DrawText(str)
|
||||
cam.IgnoreZ(false)
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
function PART:DrawBlur(ent, pos, ang)
|
||||
if pac.drawing_motionblur_alpha then return end
|
||||
self.blur_history = self.blur_history or {}
|
||||
|
||||
local blurSpacing = self.BlurSpacing
|
||||
|
||||
if not self.blur_last_add or blurSpacing == 0 or self.blur_last_add < pac.RealTime then
|
||||
table_insert(self.blur_history, {pos, ang})
|
||||
self.blur_last_add = pac.RealTime + blurSpacing / 1000
|
||||
end
|
||||
|
||||
local blurHistoryLength = #self.blur_history
|
||||
for i = 1, blurHistoryLength do
|
||||
pos, ang = self.blur_history[i][1], self.blur_history[i][2]
|
||||
|
||||
render_SetBlend(self.Alpha * (i / blurHistoryLength))
|
||||
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
pac.SetupBones(ent)
|
||||
|
||||
RealDrawModel(self, ent, pos, ang)
|
||||
end
|
||||
|
||||
local maximumBlurHistoryLength = math.min(self.BlurLength, 20)
|
||||
while #self.blur_history >= maximumBlurHistoryLength do
|
||||
table_remove(self.blur_history, 1)
|
||||
end
|
||||
end
|
||||
|
||||
local function set_mesh(part, mesh)
|
||||
local owner = part:GetOwner()
|
||||
part.Mesh = mesh
|
||||
pac.ResetBoneCache(owner)
|
||||
|
||||
if not part.Materialm then
|
||||
part.Materialm = Material("error")
|
||||
end
|
||||
|
||||
function owner.pacDrawModel(ent, simple)
|
||||
if simple then
|
||||
RealDrawModel(part, ent, ent:GetPos(), ent:GetAngles())
|
||||
else
|
||||
part:ModifiersPreEvent("OnDraw")
|
||||
part:DrawModel(ent, ent:GetPos(), ent:GetAngles())
|
||||
part:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
end
|
||||
|
||||
-- temp
|
||||
owner:SetRenderBounds(Vector(1, 1, 1) * -300, Vector(1, 1, 1) * 300)
|
||||
end
|
||||
|
||||
do
|
||||
pac.urlobj = include("pac3/libraries/urlobj/urlobj.lua")
|
||||
|
||||
function PART:SetModel(modelPath)
|
||||
if modelPath:find("^mdlhttp") then
|
||||
self.Model = modelPath
|
||||
|
||||
modelPath = modelPath:gsub("^mdl", "")
|
||||
|
||||
pac.DownloadMDL(modelPath, function(path)
|
||||
if self:IsValid() and self:GetOwner():IsValid() then
|
||||
local ent = self:GetOwner()
|
||||
self.loading = nil
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetModel(path)
|
||||
end
|
||||
end, function(err)
|
||||
pac.Message(err)
|
||||
if self:IsValid() and self:GetOwner():IsValid() then
|
||||
local ent = self:GetOwner()
|
||||
self.loading = nil
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetModel("models/error.mdl")
|
||||
end
|
||||
end, self:GetPlayerOwner())
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if modelPath and modelPath:find("http") and pac.urlobj then
|
||||
self.loading_obj = "downloading"
|
||||
|
||||
if not self.is_obj then
|
||||
self:Initialize(true)
|
||||
end
|
||||
|
||||
pac.urlobj.GetObjFromURL(modelPath, false, false,
|
||||
function(meshes, err)
|
||||
if not self:IsValid() then return end
|
||||
|
||||
self.loading_obj = false
|
||||
|
||||
if not meshes and err then
|
||||
self:GetOwner():SetModel("models/error.mdl")
|
||||
self.Mesh = nil
|
||||
return
|
||||
end
|
||||
|
||||
if table.Count(meshes) == 1 then
|
||||
set_mesh(self, select(2, next(meshes)))
|
||||
else
|
||||
for key, mesh in pairs(meshes) do
|
||||
local part = pac.CreatePart("model", self:GetParentOwnerName())
|
||||
part:SetName(key)
|
||||
part:SetParent(self)
|
||||
part:SetMaterial(self:GetMaterial())
|
||||
set_mesh(part, mesh)
|
||||
end
|
||||
|
||||
self:SetAlpha(0)
|
||||
end
|
||||
end,
|
||||
function(finished, statusMessage)
|
||||
if finished then
|
||||
self.loading_obj = nil
|
||||
else
|
||||
self.loading_obj = statusMessage
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
self.Model = modelPath
|
||||
return
|
||||
end
|
||||
|
||||
if self.is_obj or not self.Owner:IsValid() then
|
||||
self:Initialize(false)
|
||||
end
|
||||
|
||||
self.Mesh = nil
|
||||
|
||||
local real_model = modelPath
|
||||
local ret = hook.Run("pac_model:SetModel", self, modelPath, self.ModelFallback)
|
||||
if ret == nil then
|
||||
real_model = pac.FilterInvalidModel(real_model,self.ModelFallback)
|
||||
else
|
||||
modelPath = ret or modelPath
|
||||
real_model = modelPath
|
||||
real_model = pac.FilterInvalidModel(real_model,self.ModelFallback)
|
||||
end
|
||||
|
||||
self.Model = modelPath
|
||||
pac.ResetBoneCache(self.Owner)
|
||||
self.Owner:SetModel(real_model)
|
||||
|
||||
if not self:IsHidden() and not self:IsDrawHidden() then
|
||||
-- notify children about model change
|
||||
self:ShowFromRendering()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local NORMAL = Vector(1,1,1)
|
||||
|
||||
function PART:CheckScale()
|
||||
-- RenderMultiply doesn't work with this..
|
||||
if (self.UseLegacyScale or self.BoneMerge) and self.Owner:IsValid() and self.Owner:GetBoneCount() and self.Owner:GetBoneCount() > 1 then
|
||||
if self.Scale * self.Size ~= NORMAL then
|
||||
if not self.requires_bone_model_scale then
|
||||
self.requires_bone_model_scale = true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetAlternativeScaling(b)
|
||||
self.AlternativeScaling = b
|
||||
self:SetScale(self.Scale)
|
||||
end
|
||||
|
||||
function PART:SetScale(var)
|
||||
var = var or Vector(1,1,1)
|
||||
|
||||
self.Scale = var
|
||||
|
||||
if self.AlternativeScaling then
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale, nil, self.UseLegacyScale)
|
||||
self.used_alt_scale = true
|
||||
end
|
||||
else
|
||||
if self.used_alt_scale then
|
||||
pac.SetModelScale(self.Owner, nil, 1, self.UseLegacyScale)
|
||||
self.used_alt_scale = false
|
||||
end
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSize(var)
|
||||
var = var or 1
|
||||
|
||||
self.Size = var
|
||||
|
||||
if self.AlternativeScaling then
|
||||
pac.SetModelScale(self.Owner, nil, self.Size, self.UseLegacyScale)
|
||||
self.used_alt_scale = true
|
||||
else
|
||||
if self.used_alt_scale then
|
||||
pac.SetModelScale(self.Owner, nil, 1, self.UseLegacyScale)
|
||||
self.used_alt_scale = false
|
||||
end
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetBrightness(num)
|
||||
self.Brightness = num
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:SetColor(var)
|
||||
self.Color = var
|
||||
local owner = self:GetPlayerOwner()
|
||||
|
||||
if self.UsePlayerColor and owner:IsValid() then
|
||||
local c = owner:GetPlayerColor() * self.Brightness
|
||||
self.Colorf = {c.x, c.y, c.z}
|
||||
elseif self.UseWeaponColor and owner:IsValid() then
|
||||
local c = owner:GetWeaponColor() * self.Brightness
|
||||
self.Colorf = {c.x, c.y, c.z}
|
||||
else
|
||||
self.Colorf = {(var.r / 255) * self.Brightness, (var.g / 255) * self.Brightness, (var.b / 255) * self.Brightness}
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetUseWeaponColor(b)
|
||||
self.UseWeaponColor = b
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:SetUsePlayerColor(b)
|
||||
self.UsePlayerColor = b
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:FixMaterial()
|
||||
local mat = self.Materialm
|
||||
|
||||
if not mat then return end
|
||||
|
||||
local shader = mat:GetShader()
|
||||
|
||||
if shader == "UnlitGeneric" then
|
||||
local tex_path = mat:GetString("$basetexture")
|
||||
|
||||
if tex_path then
|
||||
local params = {}
|
||||
|
||||
params["$basetexture"] = tex_path
|
||||
params["$vertexcolor"] = 1
|
||||
params["$additive"] = 1
|
||||
|
||||
self.Materialm = pac.CreateMaterial(pac.uid"pac_fixmat_", "VertexLitGeneric", params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:FixMaterial()
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
end
|
||||
|
||||
function PART:SetSkin(var)
|
||||
var = var or 0
|
||||
|
||||
self.Skin = var
|
||||
self.Owner:SetSkin(var)
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if not self.OwnerEntity then
|
||||
timer.Simple(0, function()
|
||||
SafeRemoveEntity(self.Owner)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetLodOverride(num)
|
||||
local ent = self.Owner
|
||||
if ent:IsValid() then
|
||||
ent:SetLOD(num)
|
||||
self.LodOverride = num
|
||||
end
|
||||
end
|
||||
|
||||
function PART:CheckBoneMerge()
|
||||
local ent = self.Owner
|
||||
|
||||
if self.skip_orient then return end
|
||||
|
||||
if ent:IsValid() and not ent:IsPlayer() then
|
||||
if self.BoneMerge then
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if ent:GetParent() ~= owner then
|
||||
ent:SetParent(owner)
|
||||
|
||||
if not ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:AddEffects(EF_BONEMERGE)
|
||||
end
|
||||
end
|
||||
else
|
||||
if ent:GetParent():IsValid() then
|
||||
ent:SetParent(NULL)
|
||||
|
||||
if ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:RemoveEffects(EF_BONEMERGE)
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local SCALE_NORMAL = Vector(1, 1, 1)
|
||||
function PART:OnBuildBonePositions()
|
||||
if self.AlternativeScaling then return end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if not ent:IsValid() or not owner:IsValid() or not ent:GetBoneCount() or ent:GetBoneCount() < 1 then return end
|
||||
|
||||
if self.requires_bone_model_scale then
|
||||
local scale = self.Scale * self.Size
|
||||
|
||||
for i = 0, ent:GetBoneCount() - 1 do
|
||||
if i == 0 then
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * Vector(scale.x ^ 0.25, scale.y ^ 0.25, scale.z ^ 0.25))
|
||||
else
|
||||
ent:ManipulateBonePosition(i, ent:GetManipulateBonePosition(i) + Vector((scale.x-1) ^ 4, 0, 0))
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * scale)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
266
lua/pac3/core/client/parts/legacy/ogg.lua
Normal file
266
lua/pac3/core/client/parts/legacy/ogg.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
include("pac3/libraries/webaudio/urlogg.lua")
|
||||
include("pac3/libraries/webaudio/browser.lua")
|
||||
include("pac3/libraries/webaudio/stream.lua")
|
||||
include("pac3/libraries/webaudio/streams.lua")
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy ogg"
|
||||
PART.ClassName = "ogg"
|
||||
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/music.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("URL", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("Radius", 1500)
|
||||
BUILDER:GetSet("PlayCount", 1, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(math.max(num, 0))
|
||||
end})
|
||||
BUILDER:GetSet("Doppler", false)
|
||||
BUILDER:GetSet("StopOnHide", false)
|
||||
BUILDER:GetSet("PauseOnHide", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
|
||||
BUILDER:GetSet("FilterType", 0, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(math.Clamp(num, 0, 2))
|
||||
end})
|
||||
BUILDER:GetSet("FilterFraction", 1, {editor_sensitivity = 0.125, editor_clamp = {0, 1}})
|
||||
|
||||
--BUILDER:GetSet("Echo", false)
|
||||
--BUILDER:GetSet("EchoDelay", 0.5)
|
||||
--BUILDER:GetSet("EchoFeedback", 0.75)
|
||||
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("MinPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MaxPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:Initialize()
|
||||
self.streams = {}
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/".. self:GetURL())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
local stream_vars = {"Doppler", "Radius"}
|
||||
|
||||
local BIND = function(propertyName, setterMethodName, check)
|
||||
table.insert(stream_vars, propertyName)
|
||||
setterMethodName = setterMethodName or "Set" .. propertyName
|
||||
PART["Set" .. propertyName] = function(self, value)
|
||||
if check then
|
||||
value = check(value)
|
||||
end
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream[setterMethodName](stream, value)
|
||||
else
|
||||
self.streams[url] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self[propertyName] = value
|
||||
end
|
||||
end
|
||||
|
||||
BIND("Pitch", "SetPlaybackSpeed")
|
||||
BIND("PlayCount", "SetMaxLoopCount" )
|
||||
BIND("Volume", nil, function(n) return math.Clamp(n, 0, 4) end)
|
||||
BIND("Radius", "SetSourceRadius" )
|
||||
|
||||
BIND("FilterType")
|
||||
BIND("FilterFraction")
|
||||
|
||||
--BIND("Echo")
|
||||
--BIND("EchoDelay")
|
||||
--BIND("EchoFeedback", nil, function(n) return math.Clamp(n, 0, 0.99) end)
|
||||
|
||||
function PART:OnThink()
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[url] = nil goto CONTINUE end
|
||||
|
||||
if self.PlayCount == 0 then
|
||||
stream:Resume()
|
||||
end
|
||||
|
||||
if stream.owner_set ~= owner and owner:IsValid() then
|
||||
stream:SetSourceEntity(owner, true)
|
||||
stream.owner_set = owner
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
if table.Count(ent.pac_footstep_override) == 0 then
|
||||
ent.pac_footstep_override = nil
|
||||
end
|
||||
|
||||
self.last_playonfootstep = self.PlayOnFootstep
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetURL(URL)
|
||||
|
||||
local urls = {}
|
||||
|
||||
for _, url in pairs(URL:Split(";")) do
|
||||
local min, max = url:match(".+%[(.-),(.-)%]")
|
||||
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if min and max then
|
||||
for i = min, max do
|
||||
table.insert(urls, (url:gsub("%[.-%]", i)))
|
||||
end
|
||||
else
|
||||
table.insert(urls, url)
|
||||
end
|
||||
end
|
||||
|
||||
for _, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.streams = {}
|
||||
|
||||
self:SetError()
|
||||
|
||||
for _, url in pairs(urls) do
|
||||
local stream = pac.webaudio.Streams.CreateStream(url)
|
||||
self.streams[url] = stream
|
||||
|
||||
stream:Enable3D(true)
|
||||
stream.OnLoad = function()
|
||||
for _, key in ipairs(stream_vars) do
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
stream.OnError = function(err, info)
|
||||
pac.Message("OGG error: ", err, " reason: ", info or "none")
|
||||
self:SetError(str)
|
||||
end
|
||||
|
||||
if pace and pace.Editor:IsValid() and pace.current_part:IsValid() and pace.current_part.ClassName == "ogg" and self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
stream:Play()
|
||||
end
|
||||
end
|
||||
|
||||
self.URL = URL
|
||||
end
|
||||
|
||||
PART.last_stream = NULL
|
||||
|
||||
function PART:PlaySound(_, additiveVolumeFraction)
|
||||
additiveVolumeFraction = additiveVolumeFraction or 0
|
||||
local stream = table.Random(self.streams) or NULL
|
||||
|
||||
if pac.webaudio.sample_rate and pac.webaudio.sample_rate > 48000 then
|
||||
pac.Message(Color(255, 0, 0), "The ogg part (custom sounds) might not work because you have your sample rate set to ", pac.webaudio.sample_rate, " Hz. Set it to 48000 or below if you experience any issues.")
|
||||
self:SetInfo("The ogg part (custom sounds) might not work because you have your sample rate set to " .. pac.webaudio.sample_rate .. " Hz. Set it to 48000 or below if you experience any issues.")
|
||||
end
|
||||
|
||||
if not stream:IsValid() then return end
|
||||
|
||||
stream:SetAdditiveVolumeModifier (additiveVolumeFraction)
|
||||
|
||||
if self.last_stream:IsValid() and not self.Overlapping then
|
||||
self.last_stream:Stop()
|
||||
end
|
||||
|
||||
if self.MinPitch ~= self.MaxPitch then
|
||||
stream:SetAdditivePitchModifier(math.Rand(self.MinPitch, self.MaxPitch))
|
||||
else
|
||||
stream:SetAdditivePitchModifier(0)
|
||||
end
|
||||
|
||||
if self.PauseOnHide then
|
||||
stream:Resume()
|
||||
else
|
||||
stream:Start()
|
||||
end
|
||||
|
||||
self.last_stream = stream
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
if not self.StopOnHide then
|
||||
if self.PauseOnHide then
|
||||
stream:Pause()
|
||||
else
|
||||
stream:Stop()
|
||||
end
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self:PlaySound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self:StopSound()
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
stream:Remove()
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetDoppler(num)
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
stream:EnableDoppler(num)
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.Doppler = num
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
320
lua/pac3/core/client/parts/legacy/sound.lua
Normal file
320
lua/pac3/core/client/parts/legacy/sound.lua
Normal file
@@ -0,0 +1,320 @@
|
||||
--[[
|
||||
| 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_movable")
|
||||
|
||||
PART.FriendlyName = "legacy sound"
|
||||
PART.Group = "legacy"
|
||||
PART.ClassName = "sound"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/sound.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:GetSet("Sound", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Pitch", 0.4, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MinPitch", 100, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MaxPitch", 100, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("RootOwner", true)
|
||||
BUILDER:GetSet("SoundLevel", 100)
|
||||
BUILDER:GetSet("LocalPlayerOnly", false)
|
||||
BUILDER:SetPropertyGroup("playback")
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
BUILDER:GetSet("Loop", false)
|
||||
BUILDER:GetSet("Sequential", false, {description = "if there are multiple sounds (separated by ; or using [min,max] notation), plays these sounds in sequential order instead of randomly"})
|
||||
BUILDER:GetSet("SequentialStep",1,
|
||||
{editor_onchange =
|
||||
function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(num)
|
||||
end})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetSound())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
--self:PlaySound()
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self.played_overlapping = false
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self.played_overlapping = false
|
||||
self:StopSound()
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_footstep_override = nil
|
||||
|
||||
if ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
else
|
||||
if self.Loop then
|
||||
pac.playing_sound = true
|
||||
if not self.csptch:IsPlaying() then self.csptch:Play() end
|
||||
self.csptch:ChangePitch((self.Pitch * 255) + math.sin(pac.RealTime) / 2, 0)
|
||||
pac.playing_sound = false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- fixes by Python 1320
|
||||
|
||||
-- Sound protection. TODO: MAKE A BETTER FIX. Iterative removal of the special characters?
|
||||
-- This will make special sound effects break if used directly from lua, but I doubt this is common.
|
||||
-- Won't protect engine but engine shouldn't do this anyway.
|
||||
-- TODO: Beta new sound functions
|
||||
|
||||
-- https://developer.valvesoftware.com/wiki/Soundscripts#Sound_Characters
|
||||
-- we are using this for bad replacements as it won't break stuff too badly ["*"]=true,
|
||||
|
||||
local bad =
|
||||
{
|
||||
["#"] = true,
|
||||
["@"] = true,
|
||||
[">"] = true,
|
||||
["<"] = true,
|
||||
["^"] = true,
|
||||
[")"] = true,
|
||||
["}"] = true,
|
||||
["$"] = true,
|
||||
["!"] = true,
|
||||
["?"] = true, -- especially bad
|
||||
}
|
||||
|
||||
local function fix(snd)
|
||||
if bad[snd:sub(1,1)] then
|
||||
snd = snd:gsub("^(.)",function() return "*" end)
|
||||
end
|
||||
if bad[snd:sub(2,2)] then
|
||||
snd = snd:gsub("^(..)",function(a) return a[1] .. "*" end)
|
||||
end
|
||||
return snd
|
||||
end
|
||||
|
||||
function PART:SetSound(str)
|
||||
if not isstring(str) then self.Sound = "" return end
|
||||
|
||||
if bad[str:sub(1,1)] or bad[str:sub(2,2)] then
|
||||
str = fix(str)
|
||||
end
|
||||
|
||||
self.Sound = str:gsub("\\", "/")
|
||||
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
function PART:SetVolume(num)
|
||||
self.Volume = num
|
||||
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
if self.csptch then
|
||||
self.csptch:ChangeVolume(math.Clamp(self.Volume, 0.001, 1), 0)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetPitch(num)
|
||||
self.Pitch = num
|
||||
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
if self.csptch then
|
||||
self.csptch:ChangePitch(math.Clamp(self.Pitch * 255, 1, 255), 0)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PlaySound(osnd, ovol)
|
||||
local ent = self.RootOwner and self:GetRootPart():GetOwner() or self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:GetClass() == "viewmodel" or ent == pac.LocalHands then
|
||||
ent = pac.LocalPlayer
|
||||
end
|
||||
|
||||
if self:GetLocalPlayerOnly() and ent ~= pac.LocalPlayer then return end
|
||||
|
||||
local snd
|
||||
|
||||
if osnd and self.Sound == "" then
|
||||
snd = osnd
|
||||
else
|
||||
local sounds = self.Sound:Split(";")
|
||||
|
||||
--case 1: proper semicolon list
|
||||
if #sounds > 1 then
|
||||
if self.Sequential then
|
||||
self.seq_index = self.seq_index or 1
|
||||
|
||||
snd = sounds[self.seq_index]
|
||||
|
||||
self.seq_index = self.seq_index + self.SequentialStep
|
||||
self.seq_index = self.seq_index % (#sounds+1)
|
||||
if self.seq_index == 0 then self.seq_index = 1 end
|
||||
else snd = table.Random(sounds) end
|
||||
|
||||
--case 2: one sound, which may or may not be bracket notation
|
||||
elseif #sounds == 1 then
|
||||
--bracket notation
|
||||
if string.match(sounds[1],"%[(%d-),(%d-)%]") then
|
||||
local function minmaxpath(minmax,str)
|
||||
local min, max = minmax:match("%[(%d-),(%d-)%]")
|
||||
if minmax:match("%[(%d-),(%d-)%]") == nil then return 1 end
|
||||
if max < min then
|
||||
max = min
|
||||
end
|
||||
if str == "min" then return tonumber(min)
|
||||
elseif str == "max" then return tonumber(max) else return tonumber(max) end
|
||||
end
|
||||
if self.Sequential then
|
||||
self.seq_index = self.seq_index or minmaxpath(self.Sound,"min")
|
||||
snd = self.Sound:gsub(
|
||||
"(%[%d-,%d-%])",self.seq_index
|
||||
)
|
||||
self.seq_index = self.seq_index + self.SequentialStep
|
||||
|
||||
local span = minmaxpath(self.Sound,"max") - minmaxpath(self.Sound,"min") + 1
|
||||
if self.seq_index > minmaxpath(self.Sound,"max") then
|
||||
self.seq_index = self.seq_index - span
|
||||
elseif self.seq_index < minmaxpath(self.Sound,"min") then
|
||||
self.seq_index = self.seq_index + span
|
||||
end
|
||||
else
|
||||
snd = self.Sound:gsub(
|
||||
"(%[%d-,%d-%])",
|
||||
function(minmax)
|
||||
local min, max = minmax:match("%[(%d-),(%d-)%]")
|
||||
if max < min then
|
||||
max = min
|
||||
end
|
||||
return math.random(min, max)
|
||||
end
|
||||
)
|
||||
end
|
||||
--single sound
|
||||
else snd = sounds[1] or osnd end
|
||||
end
|
||||
end
|
||||
|
||||
local vol
|
||||
|
||||
if osnd and self.Volume == -1 then
|
||||
vol = ovol or 1
|
||||
else
|
||||
vol = self.Volume
|
||||
end
|
||||
|
||||
local pitch
|
||||
|
||||
if self.MinPitch == self.MaxPitch then
|
||||
pitch = self.Pitch * 255
|
||||
else
|
||||
pitch = math.random(self.MinPitch, self.MaxPitch)
|
||||
end
|
||||
|
||||
pac.playing_sound = true
|
||||
|
||||
if self.Overlapping then
|
||||
if not self.played_overlapping then
|
||||
ent:EmitSound(snd, vol * 160, pitch)
|
||||
self.played_overlapping = true
|
||||
end
|
||||
else
|
||||
if self.csptch then
|
||||
self.csptch:Stop()
|
||||
end
|
||||
|
||||
local csptch = CreateSound(ent, snd)
|
||||
|
||||
|
||||
csptch:SetSoundLevel(self.SoundLevel)
|
||||
csptch:PlayEx(vol, pitch)
|
||||
ent.pac_csptch = csptch
|
||||
self.csptch = csptch
|
||||
end
|
||||
|
||||
pac.playing_sound = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
if self.csptch then
|
||||
self.csptch:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
local channels =
|
||||
{
|
||||
CHAN_AUTO = 0,
|
||||
CHAN_WEAPON = 1,
|
||||
CHAN_VOICE = 2,
|
||||
CHAN_ITEM = 3,
|
||||
CHAN_BODY = 4,
|
||||
CHAN_STREAM = 5,
|
||||
CHAN_STATIC = 6,
|
||||
}
|
||||
|
||||
for key, CHAN in pairs(channels) do
|
||||
sound.Add(
|
||||
{
|
||||
name = "pac_silence_" .. key:lower(),
|
||||
channel = CHAN,
|
||||
volume = 0,
|
||||
soundlevel = 0,
|
||||
pitchstart = 0,
|
||||
pitchend = 0,
|
||||
sound = "ambient/_period.wav"
|
||||
} )
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
186
lua/pac3/core/client/parts/legacy/trail.lua
Normal file
186
lua/pac3/core/client/parts/legacy/trail.lua
Normal file
@@ -0,0 +1,186 @@
|
||||
--[[
|
||||
| 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 Lerp = Lerp
|
||||
local tonumber = tonumber
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
local math_ceil = math.ceil
|
||||
local math_abs = math.abs
|
||||
local render_StartBeam = render.StartBeam
|
||||
local cam_IgnoreZ = cam.IgnoreZ
|
||||
local render_EndBeam = render.EndBeam
|
||||
local render_AddBeam = render.AddBeam
|
||||
local render_SetMaterial = render.SetMaterial
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy trail"
|
||||
PART.ClassName = "trail"
|
||||
PART.Group = "legacy"
|
||||
|
||||
PART.Icon = 'icon16/arrow_undo.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("TrailPath", "trails/laser", {editor_panel = "material"})
|
||||
BUILDER:GetSet("StartSize", 3)
|
||||
BUILDER:GetSet("EndSize", 0)
|
||||
BUILDER:GetSet("Length", 100)
|
||||
BUILDER:GetSet("Spacing", 1)
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("StartColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("EndColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("StartAlpha", 1)
|
||||
BUILDER:GetSet("EndAlpha", 1)
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Stretch", false)
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetTrailPath())
|
||||
local matched = str and str:match(".+/(.+)")
|
||||
return matched and matched:gsub("%..+", "") or "error"
|
||||
end
|
||||
|
||||
PART.LastAdd = 0
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetTrailPath(self.TrailPath)
|
||||
|
||||
self.StartColorC = Color(255, 255, 255, 255)
|
||||
self.EndColorC = Color(255, 255, 255, 255)
|
||||
end
|
||||
|
||||
function PART:SetStartColor(v)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.r = v.r
|
||||
self.StartColorC.g = v.g
|
||||
self.StartColorC.b = v.b
|
||||
|
||||
self.StartColor = v
|
||||
end
|
||||
|
||||
function PART:SetEndColor(v)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.r = v.r
|
||||
self.EndColorC.g = v.g
|
||||
self.EndColorC.b = v.b
|
||||
|
||||
self.EndColor = v
|
||||
end
|
||||
|
||||
function PART:SetStartAlpha(n)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.a = n * 255
|
||||
|
||||
self.StartAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetEndAlpha(n)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.a = n * 255
|
||||
|
||||
self.EndAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetTrailPath(var)
|
||||
self.TrailPath = var
|
||||
self:SetMaterial(var)
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if isstring(var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
elseif type(var) == "IMaterial" then
|
||||
self.Materialm = var
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
if self.Materialm then
|
||||
local shader = self.Materialm:GetShader()
|
||||
if shader == "VertexLitGeneric" or shader == "Cable" or shader == "LightmappedGeneric" then
|
||||
self.Materialm = pac.MakeMaterialUnlitGeneric(self.Materialm, self.Id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
local temp_color = Color(255, 255, 255)
|
||||
|
||||
function PART:OnDraw()
|
||||
local mat = self.MaterialOverride or self.Materialm
|
||||
|
||||
if mat and self.StartColorC and self.EndColorC then
|
||||
self.points = self.points or {}
|
||||
|
||||
local len = tonumber(self.Length)
|
||||
local spc = tonumber(self.Spacing)
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
if spc == 0 or self.LastAdd < pac.RealTime then
|
||||
table_insert(self.points, pos)
|
||||
self.LastAdd = pac.RealTime + spc / 1000
|
||||
end
|
||||
|
||||
local count = #self.points
|
||||
|
||||
if spc > 0 then
|
||||
len = math_ceil(math_abs(len - spc))
|
||||
end
|
||||
|
||||
render_SetMaterial(mat)
|
||||
|
||||
render_StartBeam(count)
|
||||
for k, v in pairs(self.points) do
|
||||
local width = k / (len / self.StartSize)
|
||||
|
||||
local coord = (1 / count) * (k - 1)
|
||||
|
||||
temp_color.r = Lerp(coord, self.EndColorC.r, self.StartColorC.r)
|
||||
temp_color.g = Lerp(coord, self.EndColorC.g, self.StartColorC.g)
|
||||
temp_color.b = Lerp(coord, self.EndColorC.b, self.StartColorC.b)
|
||||
temp_color.a = Lerp(coord, self.EndColorC.a, self.StartColorC.a)
|
||||
|
||||
render_AddBeam(k == count and pos or v, width + self.EndSize, self.Stretch and coord or width, temp_color)
|
||||
end
|
||||
render_EndBeam()
|
||||
|
||||
if count >= len then
|
||||
table_remove(self.points, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
330
lua/pac3/core/client/parts/legacy/webaudio.lua
Normal file
330
lua/pac3/core/client/parts/legacy/webaudio.lua
Normal file
@@ -0,0 +1,330 @@
|
||||
--[[
|
||||
| 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_drawable")
|
||||
local snd_mute_losefocus = GetConVar('snd_mute_losefocus')
|
||||
|
||||
PART.FriendlyName = "legacy webaudio"
|
||||
PART.ClassName = "webaudio"
|
||||
PART.Group = 'legacy'
|
||||
PART.Icon = 'icon16/sound_add.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("URL", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MinimumRadius", 0)
|
||||
BUILDER:GetSet("MaximumRadius", 0)
|
||||
|
||||
BUILDER:GetSet("InnerAngle", 360)
|
||||
BUILDER:GetSet("OuterAngle", 360)
|
||||
BUILDER:GetSet("OuterVolume", 0)
|
||||
|
||||
BUILDER:GetSet("Loop", false)
|
||||
BUILDER:GetSet("StopOnHide", true)
|
||||
BUILDER:GetSet("PauseOnHide", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("RandomPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:Initialize()
|
||||
self.streams = {}
|
||||
self.stream_count = 0
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetURL())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
if table.Count(ent.pac_footstep_override) == 0 then
|
||||
ent.pac_footstep_override = nil
|
||||
end
|
||||
|
||||
self.last_playonfootstep = self.PlayOnFootstep
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not self.streams then return end
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
local forward = ang:Forward()
|
||||
|
||||
local shouldMute = snd_mute_losefocus:GetBool()
|
||||
local focus = system.HasFocus()
|
||||
local volume = shouldMute and not focus and 0 or self:GetVolume()
|
||||
|
||||
for url, streamdata in pairs(self.streams) do
|
||||
local stream = streamdata.stream
|
||||
if streamdata.Loading then goto CONTINUE end
|
||||
|
||||
if not stream:IsValid() then
|
||||
self.streams[url] = nil
|
||||
self.stream_count = self.stream_count - 1
|
||||
-- TODO: Notify the user somehow or reload streams
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
stream:SetPos(pos, forward)
|
||||
|
||||
if not self.random_pitch then self:SetRandomPitch(self.RandomPitch) end
|
||||
|
||||
stream:Set3DFadeDistance(self.MinimumRadius, self.MaximumRadius)
|
||||
stream:Set3DCone(self.InnerAngle, self.OuterAngle, self.OuterVolume)
|
||||
stream:SetVolume(volume)
|
||||
stream:SetPlaybackRate(self:GetPitch() + self.random_pitch)
|
||||
|
||||
if streamdata.StartPlaying then
|
||||
stream:Play()
|
||||
streamdata.StartPlaying = false
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetRandomPitch(num)
|
||||
self.RandomPitch = num
|
||||
self.random_pitch = math.Rand(-num, num)
|
||||
end
|
||||
|
||||
function PART:SetLoop(b)
|
||||
self.Loop = b
|
||||
self:SetURL(self:GetURL())
|
||||
end
|
||||
|
||||
function PART:SetURL(URL)
|
||||
self.InSetup = true
|
||||
|
||||
timer.Create("pac3_webaudio_seturl_" .. tostring(self), 0.5, 1, function()
|
||||
if not self:IsValid() then return end
|
||||
|
||||
self.InSetup = false
|
||||
self:SetupURLStreamsNow(URL)
|
||||
|
||||
if self.PlayAfterSetup then
|
||||
self:PlaySound()
|
||||
self.PlayAfterSetup = false
|
||||
end
|
||||
end)
|
||||
|
||||
self.URL = URL
|
||||
end
|
||||
|
||||
function PART:SetupURLStreamsNow(URL)
|
||||
local urls = {}
|
||||
|
||||
for _, url in ipairs(URL:Split(";")) do
|
||||
local min, max = url:match(".+%[(.-),(.-)%]")
|
||||
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if min and max then
|
||||
for i = min, max do
|
||||
table.insert(urls, (url:gsub("%[.-%]", i)))
|
||||
end
|
||||
else
|
||||
table.insert(urls, url)
|
||||
end
|
||||
end
|
||||
|
||||
if #urls >= 150 then
|
||||
local cp = {}
|
||||
|
||||
for i = 1, 150 do
|
||||
table.insert(cp, urls[i])
|
||||
end
|
||||
|
||||
urls = cp
|
||||
end
|
||||
|
||||
for url, streamdata in pairs(self.streams) do
|
||||
if IsValid(streamdata.stream) then
|
||||
streamdata.stream:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
self.streams = {}
|
||||
self.stream_count = 0
|
||||
|
||||
local inPace = pace and pace.IsActive() and pace.current_part == self and self:GetPlayerOwner() == pac.LocalPlayer
|
||||
|
||||
for _, url in ipairs(urls) do
|
||||
local flags = "3d noplay noblock"
|
||||
local function callback(channel, errorCode, errorString)
|
||||
local streamdata = self.streams[url]
|
||||
if not streamdata then
|
||||
if IsValid(channel) then channel:Stop() end
|
||||
return
|
||||
end
|
||||
|
||||
if not channel or not channel:IsValid() then
|
||||
pac.Message("Failed to load ", url, " (" .. flags .. ") - " .. (errorString or errorCode or "UNKNOWN"))
|
||||
self:SetError("Failed to load " .. url .. " (" .. flags .. ") - " .. (errorString or errorCode or "UNKNOWN"))
|
||||
|
||||
if errorCode == -1 then
|
||||
local msg = 'GMOD BUG: WAVe and Vorbis files are known to be not working with 3D flag, recode file into MPEG-3 format!'
|
||||
pac.Message(msg)
|
||||
self:SetError(msg)
|
||||
end
|
||||
|
||||
self.streams[url] = nil
|
||||
self.stream_count = self.stream_count - 1
|
||||
return
|
||||
end
|
||||
|
||||
streamdata.Loading = false
|
||||
|
||||
if streamdata.valid then
|
||||
if streamdata.PlayAfterLoad or inPace then
|
||||
channel:EnableLooping(self.Loop and channel:GetLength() > 0)
|
||||
streamdata.PlayAfterLoad = false
|
||||
streamdata.StartPlaying = true
|
||||
end
|
||||
|
||||
streamdata.stream = channel
|
||||
|
||||
if self.NeedsToPlayAfterLoad then
|
||||
self.NeedsToPlayAfterLoad = false
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
channel:Stop()
|
||||
end
|
||||
|
||||
self.streams[url] = {Loading = true, valid = true}
|
||||
self.stream_count = self.stream_count + 1
|
||||
|
||||
sound.PlayURL(url, flags, callback)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PlaySound()
|
||||
if self.InSetup then
|
||||
self.PlayAfterSetup = true
|
||||
return
|
||||
end
|
||||
|
||||
if self.stream_count == 0 then return end
|
||||
|
||||
local i, streamdata, atLeastSome = 0
|
||||
|
||||
while i < 20 and i < self.stream_count do
|
||||
streamdata = table.Random(self.streams)
|
||||
|
||||
if IsValid(streamdata.stream) then
|
||||
if not atLeastSome and streamdata.Loading then
|
||||
atLeastSome = true
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
local stream = streamdata.stream
|
||||
|
||||
if not IsValid(stream) then
|
||||
if atLeastSome then
|
||||
self.NeedsToPlayAfterLoad = true
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:SetRandomPitch(self.RandomPitch)
|
||||
|
||||
if IsValid(self.last_stream) and not self.Overlapping and self.last_stream ~= stream then
|
||||
pcall(function()
|
||||
-- this is erroring with noblock flag not being set, but we are doing that
|
||||
-- maybe the stream could be partially invalid
|
||||
self.last_stream:SetTime(0)
|
||||
self.last_stream:Pause()
|
||||
end)
|
||||
end
|
||||
|
||||
streamdata.StartPlaying = true
|
||||
self.last_stream = stream
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
local toremove
|
||||
|
||||
for key, streamdata in pairs(self.streams) do
|
||||
streamdata.PlayAfterLoad = false
|
||||
streamdata.StartPlaying = false
|
||||
|
||||
local stream = streamdata.stream
|
||||
|
||||
if IsValid(stream) then
|
||||
if self.PauseOnHide then
|
||||
stream:Pause()
|
||||
else
|
||||
pcall(function() stream:SetTime(0) end)
|
||||
stream:Pause()
|
||||
end
|
||||
elseif stream then
|
||||
toremove = toremove or {}
|
||||
table.insert(toremove, key)
|
||||
end
|
||||
end
|
||||
|
||||
if toremove then
|
||||
for i, index in ipairs(toremove) do
|
||||
self.streams[index] = nil
|
||||
end
|
||||
|
||||
self.stream_count = self.stream_count - #toremove
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self:PlaySound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
if self.StopOnHide then
|
||||
self:StopSound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
for key, streamdata in pairs(self.streams) do
|
||||
streamdata.valid = false
|
||||
|
||||
if IsValid(streamdata.stream) then
|
||||
streamdata.stream:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
123
lua/pac3/core/client/parts/light.lua
Normal file
123
lua/pac3/core/client/parts/light.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--[[
|
||||
| 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 DynamicLight = DynamicLight
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "light"
|
||||
PART.ClassName = "light2"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/lightbulb.png'
|
||||
PART.ProperColorRange = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("InnerAngle", 0)
|
||||
BUILDER:GetSet("OuterAngle", 0)
|
||||
BUILDER:GetSet("NoModel", false)
|
||||
BUILDER:GetSet("NoWorld", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Brightness", 8)
|
||||
BUILDER:GetSet("Size", 100, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Color", Vector(1, 1, 1), {editor_panel = "color2"})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetLight()
|
||||
if not self.light then
|
||||
self.light = DynamicLight(tonumber(self:GetPrintUniqueID(), 16))
|
||||
end
|
||||
self.light.decay = 0
|
||||
self.light.dietime = math.huge
|
||||
|
||||
return self.light
|
||||
end
|
||||
|
||||
function PART:RemoveLight()
|
||||
if not self.light then return end
|
||||
local light = self.light
|
||||
self.light = nil
|
||||
-- this prevents fade out when removing the light
|
||||
light.pos = Vector(9999, 9999, 9999)
|
||||
timer.Simple(0, function()
|
||||
light.dietime = 0
|
||||
end)
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local color = self:GetColor()
|
||||
local hue = pac.ColorToNames({r = color[1] * 255, g = color[2] * 255, b = color[3] * 255})
|
||||
return hue .. " light"
|
||||
end
|
||||
|
||||
local vars = {
|
||||
"InnerAngle",
|
||||
"OuterAngle",
|
||||
"NoWorld",
|
||||
"NoModel",
|
||||
"Brightness",
|
||||
"Color",
|
||||
"Size",
|
||||
}
|
||||
|
||||
function PART:OnShow()
|
||||
for _, v in ipairs(vars) do
|
||||
self["Set" .. v](self, self["Get" .. v](self))
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:GetLight().pos = pos
|
||||
self:GetLight().dir = ang:Forward()
|
||||
end
|
||||
|
||||
function PART:SetSize(val)
|
||||
self.Size = val
|
||||
self:GetLight().size = val
|
||||
end
|
||||
|
||||
function PART:SetColor(val)
|
||||
self.Color = val
|
||||
self:GetLight().r = math.Clamp(val.r * 255, 0, 255)
|
||||
self:GetLight().g = math.Clamp(val.g * 255, 0, 255)
|
||||
self:GetLight().b = math.Clamp(val.b * 255, 0, 255)
|
||||
end
|
||||
|
||||
function PART:SetBrightness(val)
|
||||
self.Brightness = val
|
||||
self:GetLight().brightness = val
|
||||
end
|
||||
|
||||
function PART:SetNoModel(val)
|
||||
self.NoModel = val
|
||||
self:GetLight().nomodel = val
|
||||
end
|
||||
|
||||
function PART:SetNoWorld(val)
|
||||
self.NoWorld = val
|
||||
self:GetLight().noworld = val
|
||||
end
|
||||
|
||||
function PART:SetInnerAngle(val)
|
||||
self.InnerAngle = val
|
||||
self:GetLight().innerangle = val
|
||||
end
|
||||
|
||||
function PART:SetOuterAngle(val)
|
||||
self.OuterAngle = val
|
||||
self:GetLight().outerangle = val
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self:RemoveLight()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
72
lua/pac3/core/client/parts/link.lua
Normal file
72
lua/pac3/core/client/parts/link.lua
Normal file
@@ -0,0 +1,72 @@
|
||||
--[[
|
||||
| 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 = "link"
|
||||
|
||||
PART.Group = 'advanced'
|
||||
PART.Icon = 'icon16/weather_clouds.png'
|
||||
|
||||
local function fill_enums(target)
|
||||
if not target:IsValid() then return end
|
||||
|
||||
local tbl = {}
|
||||
for _, prop in pairs(target:GetProperties()) do
|
||||
if prop.key == "UniqueID" then goto CONTINUE end
|
||||
|
||||
local T = type(prop.get())
|
||||
if T == "number" or T == "Vector" or T == "Angle" or T == "boolean" then
|
||||
tbl[prop.key] = prop.key
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSetPart("From")
|
||||
BUILDER:GetSetPart("To")
|
||||
BUILDER:GetSet("Type", "from -> to", {enums = {"from -> to", "to -< from", "from <-> to"}})
|
||||
BUILDER:GetSet("FromVariableName", "", {enums = function(self) return fill_enums(self:GetFrom()) end})
|
||||
BUILDER:GetSet("ToVariableName", "", {enums = function(self) return fill_enums(self:GetTo()) end})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local function hook_property(a, b, a_prop, b_prop, callback)
|
||||
if not a["Get" .. a_prop] or not a["Set" .. a_prop] then return end
|
||||
if not b["Get" .. b_prop] or not b["Set" .. b_prop] then return end
|
||||
end
|
||||
|
||||
function PART:SetFrom(from)
|
||||
self.From = from
|
||||
|
||||
if self.FromVariableName == "" then return end
|
||||
if not from:IsValid() then return end
|
||||
|
||||
if not from["Set" .. self.FromVariableName] then return end
|
||||
|
||||
local old_from_setter = from["Set" .. self.FromVariableName]
|
||||
local from_getter = from["Get" .. self.FromVariableName]
|
||||
from["Set" .. self.FromVariableName] = function(s, v)
|
||||
old_from_setter(s, v)
|
||||
|
||||
local to = self:GetTo()
|
||||
if self.ToVariableName == "" then return end
|
||||
if not to:IsValid() then return end
|
||||
|
||||
local to_setter = to["Set" .. self.FromVariableName]
|
||||
if not to_setter then return end
|
||||
|
||||
to_setter(to, from_getter(from))
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
609
lua/pac3/core/client/parts/material.lua
Normal file
609
lua/pac3/core/client/parts/material.lua
Normal file
@@ -0,0 +1,609 @@
|
||||
--[[
|
||||
| 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 shader_params = include("pac3/libraries/shader_params.lua")
|
||||
|
||||
local mat_hdr_level = GetConVar("mat_hdr_level")
|
||||
|
||||
local material_flags = {
|
||||
debug = bit.lshift(1, 0),
|
||||
no_debug_override = bit.lshift(1, 1),
|
||||
no_draw = bit.lshift(1, 2),
|
||||
use_in_fillrate_mode = bit.lshift(1, 3),
|
||||
vertexcolor = bit.lshift(1, 4),
|
||||
vertexalpha = bit.lshift(1, 5),
|
||||
selfillum = bit.lshift(1, 6),
|
||||
additive = bit.lshift(1, 7),
|
||||
alphatest = bit.lshift(1, 8),
|
||||
multipass = bit.lshift(1, 9),
|
||||
znearer = bit.lshift(1, 10),
|
||||
model = bit.lshift(1, 11),
|
||||
flat = bit.lshift(1, 12),
|
||||
nocull = bit.lshift(1, 13),
|
||||
nofog = bit.lshift(1, 14),
|
||||
ignorez = bit.lshift(1, 15),
|
||||
decal = bit.lshift(1, 16),
|
||||
envmapsphere = bit.lshift(1, 17),
|
||||
noalphamod = bit.lshift(1, 18),
|
||||
envmapcameraspace = bit.lshift(1, 19),
|
||||
basealphaenvmapmask = bit.lshift(1, 20),
|
||||
translucent = bit.lshift(1, 21),
|
||||
normalmapalphaenvmapmask = bit.lshift(1, 22),
|
||||
needs_software_skinning = bit.lshift(1, 23),
|
||||
opaquetexture = bit.lshift(1, 24),
|
||||
envmapmode = bit.lshift(1, 25),
|
||||
suppress_decals = bit.lshift(1, 26),
|
||||
halflambert = bit.lshift(1, 27),
|
||||
wireframe = bit.lshift(1, 28),
|
||||
allowalphatocoverage = bit.lshift(1, 29),
|
||||
ignore_alpha_modulation = bit.lshift(1, 30),
|
||||
}
|
||||
|
||||
local function TableToFlags(flags, valid_flags)
|
||||
if isstring(flags) then
|
||||
flags = {flags}
|
||||
end
|
||||
|
||||
local out = 0
|
||||
|
||||
for k, v in pairs(flags) do
|
||||
if v then
|
||||
local flag = valid_flags[v] or valid_flags[k]
|
||||
if not flag then
|
||||
error("invalid flag", 2)
|
||||
end
|
||||
|
||||
out = bit.bor(out, tonumber(flag))
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function FlagsToTable(flags, valid_flags)
|
||||
|
||||
if not flags then return valid_flags.default_valid_flag end
|
||||
|
||||
local out = {}
|
||||
|
||||
for k, v in pairs(valid_flags) do
|
||||
if bit.band(flags, v) > 0 then
|
||||
out[k] = true
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local shader_name_translate = {
|
||||
vertexlitgeneric = "3d",
|
||||
unlitgeneric = "2d",
|
||||
eyerefract = "eye refract",
|
||||
}
|
||||
|
||||
for shader_name, groups in pairs(shader_params.shaders) do
|
||||
for group_name, base_group in pairs(shader_params.base) do
|
||||
if groups[group_name] then
|
||||
for k,v in pairs(base_group) do
|
||||
if not groups[group_name][k] then
|
||||
groups[group_name][k] = v
|
||||
end
|
||||
end
|
||||
else
|
||||
groups[group_name] = base_group
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for shader_name, groups in pairs(shader_params.shaders) do
|
||||
local temp = CreateMaterial(tostring({}), shader_name, {})
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
PART.ClassName = "material_" .. (shader_name_translate[shader_name] or shader_name)
|
||||
PART.Description = shader_name
|
||||
|
||||
PART.ProperColorRange = true
|
||||
|
||||
if shader_name == "vertexlitgeneric" then
|
||||
PART.FriendlyName = "material"
|
||||
PART.Group = {'modifiers', 'model', 'entity'}
|
||||
else
|
||||
PART.FriendlyName = "material " .. shader_name
|
||||
PART.Group = "advanced"
|
||||
end
|
||||
|
||||
PART.Icon = "icon16/paintcan.png"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
|
||||
-- move this to tools or something
|
||||
BUILDER:GetSet("LoadVmt", "", {editor_panel = "material"})
|
||||
function PART:SetLoadVmt(path)
|
||||
if not path or path == "" then return end
|
||||
|
||||
local str = file.Read("materials/" .. path .. ".vmt", "GAME")
|
||||
|
||||
if not str then return end
|
||||
|
||||
local vmt = util.KeyValuesToTable(str)
|
||||
local shader = str:match("^(.-)%{"):gsub("%p", ""):Trim()
|
||||
|
||||
|
||||
for k,v in pairs(self:GetVars()) do
|
||||
local param = PART.ShaderParams[k]
|
||||
if param and param.default ~= nil then
|
||||
self["Set" .. k](self, param.default)
|
||||
end
|
||||
if param and param.type == "texture" then
|
||||
self["Set" .. k](self, "")
|
||||
end
|
||||
end
|
||||
|
||||
print(str)
|
||||
print("======")
|
||||
PrintTable(vmt)
|
||||
print("======")
|
||||
|
||||
for k,v in pairs(vmt) do
|
||||
if k:StartWith("$") then k = k:sub(2) end
|
||||
|
||||
local func = self["Set" .. k]
|
||||
if func then
|
||||
local info = PART.ShaderParams[k]
|
||||
|
||||
if isstring(v) then
|
||||
if v:find("[", nil, true) then
|
||||
v = Vector(v:gsub("[%[%]]", ""):gsub("%s+", " "):Trim())
|
||||
|
||||
if isnumber(info.default) then
|
||||
v = v.x
|
||||
end
|
||||
elseif v:find("{", nil, true) then
|
||||
v = Vector(v:gsub("[%{%}]", ""):gsub("%s+", " "):Trim())
|
||||
|
||||
if info.type == "color" then
|
||||
v = v / 255
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if isnumber(v) then
|
||||
if info.type == "bool" or info.is_flag then
|
||||
v = v == 1
|
||||
end
|
||||
end
|
||||
|
||||
func(self, v)
|
||||
else
|
||||
pac.Message("cannot convert material parameter " .. k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:GetSet("MaterialOverride", "all", {enums = function(self, str)
|
||||
|
||||
local materials = {}
|
||||
|
||||
if pace.current_part:GetOwner():IsValid() then
|
||||
materials = pace.current_part:GetOwner():GetMaterials()
|
||||
end
|
||||
|
||||
table.insert(materials, "all")
|
||||
|
||||
local tbl = {}
|
||||
|
||||
for _, v in ipairs(materials) do
|
||||
v = v:match(".+/(.+)") or v
|
||||
tbl[v] = v:lower()
|
||||
end
|
||||
|
||||
return tbl
|
||||
end})
|
||||
|
||||
local function update_submaterial(self, remove, parent)
|
||||
pac.RunNextFrameSimple(function()
|
||||
if not IsValid(self) and not remove then return end
|
||||
local name = self:GetName()
|
||||
|
||||
for _, part in ipairs(self:GetRootPart():GetChildrenList()) do
|
||||
if part.GetMaterials then
|
||||
for _, path in ipairs(part.Materials:Split(";")) do
|
||||
if path == name then
|
||||
part:SetMaterials(part.Materials)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local str = self.MaterialOverride
|
||||
parent = parent or self:GetParent()
|
||||
|
||||
local num = 0
|
||||
|
||||
if parent:IsValid() then
|
||||
if tonumber(str) then
|
||||
num = tonumber(str)
|
||||
elseif str ~= "all" and parent:GetOwner():IsValid() then
|
||||
for i, v in ipairs(parent:GetOwner():GetMaterials()) do
|
||||
if (v:match(".+/(.+)") or v):lower() == str:lower() then
|
||||
num = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parent.material_override = parent.material_override or {}
|
||||
parent.material_override[num] = parent.material_override[num] or {}
|
||||
|
||||
for _, stack in pairs(parent.material_override) do
|
||||
for i, v in ipairs(stack) do
|
||||
if v == self then
|
||||
table.remove(stack, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not remove then
|
||||
table.insert(parent.material_override[num], self)
|
||||
end
|
||||
end
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self.translation_vector = Vector()
|
||||
self.rotation_angle = Angle(0, 0, 0)
|
||||
end
|
||||
|
||||
|
||||
function PART:GetNiceName()
|
||||
local path = ""
|
||||
|
||||
if shader_name == "refract" then
|
||||
path = self:Getnormalmap()
|
||||
elseif shader_name == "eyerefract" then
|
||||
path = self:Getiris()
|
||||
else
|
||||
path = self:Getbasetexture()
|
||||
end
|
||||
|
||||
path = path:gsub("%%(..)", function(char)
|
||||
local num = tonumber("0x" .. char)
|
||||
if num then
|
||||
return string.char(num)
|
||||
end
|
||||
end)
|
||||
|
||||
local name = ("/".. path):match(".+/(.-)%.") or ("/".. path):match(".+/(.+)")
|
||||
local nice_name = (pac.PrettifyName(name) or "no texture") .. " | " .. shader_name
|
||||
|
||||
return nice_name
|
||||
end
|
||||
|
||||
function PART:SetMaterialOverride(num)
|
||||
self.MaterialOverride = num
|
||||
|
||||
update_submaterial(self)
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if self:GetOwner():IsValid() then
|
||||
local materials = self:GetOwner():GetMaterials()
|
||||
if materials and #materials ~= self.last_material_count then
|
||||
update_submaterial(self)
|
||||
self.last_material_count = #materials
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
PART.ShaderParams = {}
|
||||
PART.TransformVars = {}
|
||||
|
||||
local sorted_groups = {}
|
||||
for k, v in pairs(groups) do
|
||||
table.insert(sorted_groups, {k = k, v = v})
|
||||
end
|
||||
table.sort(sorted_groups, function(a, b) return a.k:lower() < b.k:lower() end)
|
||||
|
||||
for _, v in ipairs(sorted_groups) do
|
||||
local group, params = v.k, v.v
|
||||
|
||||
local sorted_params = {}
|
||||
for k, v in pairs(params) do
|
||||
table.insert(sorted_params, {k = k, v = v})
|
||||
end
|
||||
table.sort(sorted_params, function(a, b) return a.k:lower() < b.k:lower() end)
|
||||
|
||||
for _, v in ipairs(sorted_params) do
|
||||
local key, info = v.k, v.v
|
||||
|
||||
PART.ShaderParams[key] = info
|
||||
|
||||
if info.is_flag and group == "generic" then
|
||||
BUILDER:SetPropertyGroup("flags")
|
||||
else
|
||||
BUILDER:SetPropertyGroup(group)
|
||||
end
|
||||
|
||||
if info.default == nil then
|
||||
if info.type == "vec3" then
|
||||
info.default = Vector(0,0,0)
|
||||
elseif info.type == "color" then
|
||||
info.default = Vector(1,1,1)
|
||||
elseif info.type == "float" then
|
||||
info.default = 0
|
||||
elseif info.type == "vec2" then
|
||||
info.default = Vector(0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local property_name = key
|
||||
|
||||
local description = (info.description or "") .. " ($" .. key .. ")"
|
||||
|
||||
if info.type == "matrix" then
|
||||
local position_key = property_name .. "Position"
|
||||
local scale_key = property_name .. "Scale"
|
||||
local angle_key = property_name .. "Angle"
|
||||
local angle_center_key = property_name .. "AngleCenter"
|
||||
|
||||
local friendly_name = info.friendly:gsub("Transform", "")
|
||||
BUILDER:GetSet(position_key, Vector(0, 0, 0), {editor_friendly = friendly_name .. "Position", description = description})
|
||||
BUILDER:GetSet(scale_key, Vector(1, 1, 1), {editor_friendly = friendly_name .. "Scale", description = description})
|
||||
BUILDER:GetSet(angle_key, 0, {editor_panel = "number", editor_friendly = friendly_name .. "Angle", description = description})
|
||||
BUILDER:GetSet(angle_center_key, Vector(0.5, 0.5, 0), {editor_friendly = friendly_name .. "AngleCenter", description = description})
|
||||
|
||||
PART.TransformVars[position_key] = true
|
||||
PART.TransformVars[scale_key] = true
|
||||
PART.TransformVars[angle_key] = true
|
||||
PART.TransformVars[angle_center_key] = true
|
||||
|
||||
local shader_key = "$" .. key
|
||||
|
||||
local function setup_matrix(self)
|
||||
self.matrix = self.matrix or Matrix()
|
||||
|
||||
self.matrix:Identity()
|
||||
self.matrix:Translate(self.translation_vector)
|
||||
|
||||
self.matrix:Translate(self[angle_center_key])
|
||||
self.matrix:Rotate(self.rotation_angle)
|
||||
self.matrix:Translate(-self[angle_center_key])
|
||||
|
||||
self.matrix:SetScale(self[scale_key])
|
||||
end
|
||||
|
||||
PART["Set" .. position_key] = function(self, vec)
|
||||
self[position_key] = vec
|
||||
|
||||
|
||||
self.translation_vector.x = self[position_key].x
|
||||
self.translation_vector.y = self[position_key].y
|
||||
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. scale_key] = function(self, vec)
|
||||
self[scale_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_key] = function(self, num)
|
||||
self[angle_key] = num
|
||||
|
||||
self.rotation_angle.y = self[angle_key]*360
|
||||
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_center_key] = function(self, vec)
|
||||
self[angle_center_key] = vec
|
||||
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
elseif info.type == "texture" then
|
||||
local getnohdr = "Get" .. property_name .. "NoHDR"
|
||||
|
||||
if info.partial_hdr then
|
||||
BUILDER:GetSet(property_name .. "NoHDR", false, {
|
||||
editor_friendly = info.friendly .. " No HDR",
|
||||
description = "Disables bound param when HDR is enabled",
|
||||
})
|
||||
end
|
||||
|
||||
info.default = info.default or ""
|
||||
|
||||
BUILDER:GetSet(property_name, info.default, {
|
||||
editor_panel = "textures",
|
||||
editor_friendly = info.friendly,
|
||||
description = description,
|
||||
shader_param_info = info,
|
||||
})
|
||||
|
||||
local key = "$" .. key
|
||||
|
||||
PART["Set" .. property_name .. "NoHDR"] = function(self, val)
|
||||
self[property_name .. "NoHDR"] = val
|
||||
PART["Set" .. property_name](self, self[property_name])
|
||||
end
|
||||
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
self[property_name] = val
|
||||
|
||||
if val == "" or info.partial_hdr and mat_hdr_level:GetInt() > 0 and self[getnohdr](self) then
|
||||
self:GetRawMaterial():SetUndefined(key)
|
||||
self:GetRawMaterial():Recompute()
|
||||
else
|
||||
if not pac.resource.DownloadTexture(val, function(tex, frames)
|
||||
if frames then
|
||||
self.vtf_frame_limit = self.vtf_frame_limit or {}
|
||||
self.vtf_frame_limit[property_name] = frames
|
||||
end
|
||||
self:GetRawMaterial():SetTexture(key, tex)
|
||||
end, self:GetPlayerOwner()) then
|
||||
self:GetRawMaterial():SetTexture(key, val)
|
||||
|
||||
local texture = self:GetRawMaterial():GetTexture(key)
|
||||
|
||||
if texture then
|
||||
self.vtf_frame_limit = self.vtf_frame_limit or {}
|
||||
self.vtf_frame_limit[property_name] = texture:GetNumAnimationFrames()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
BUILDER:GetSet(property_name, info.default, {
|
||||
editor_friendly = info.friendly,
|
||||
enums = info.enums,
|
||||
description = description,
|
||||
editor_sensitivity = (info.type == "vec3" or info.type == "color") and 0.25 or nil,
|
||||
editor_panel = (info.type == "color" and "color2") or (property_name == "model" and "boolean") or nil,
|
||||
editor_round = info.type == "integer",
|
||||
})
|
||||
|
||||
local flag_key = key
|
||||
local key = "$" .. key
|
||||
|
||||
if isnumber(info.default) then
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
self[property_name] = val
|
||||
local mat = self:GetRawMaterial()
|
||||
mat:SetFloat(key, val)
|
||||
if info.recompute then
|
||||
mat:Recompute()
|
||||
end
|
||||
end
|
||||
if property_name:lower():find("frame") then
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
self[property_name] = val
|
||||
if self.vtf_frame_limit and info.linked and self.vtf_frame_limit[info.linked] then
|
||||
self:GetRawMaterial():SetInt(key, math.abs(val)%self.vtf_frame_limit[info.linked])
|
||||
else
|
||||
self:GetRawMaterial():SetInt(key, val)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif isbool(info.default) then
|
||||
if info.is_flag then
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
self[property_name] = val
|
||||
|
||||
local mat = self:GetRawMaterial()
|
||||
|
||||
local tbl = FlagsToTable(mat:GetInt("$flags"), material_flags)
|
||||
tbl[flag_key] = val
|
||||
mat:SetInt("$flags", TableToFlags(tbl, material_flags))
|
||||
|
||||
mat:Recompute()
|
||||
end
|
||||
else
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
if isvector(val) then
|
||||
val = (val == Vector(1,1,1)) and true or false
|
||||
end
|
||||
|
||||
self[property_name] = val
|
||||
local mat = self:GetRawMaterial()
|
||||
|
||||
mat:SetInt(key, val and 1 or 0)
|
||||
if info.recompute then mat:Recompute() end
|
||||
end
|
||||
end
|
||||
elseif isvector(info.default) or info.type == "vec3" or info.type == "vec2" then
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
if isstring(val) then val = Vector() end
|
||||
self[property_name] = val
|
||||
local mat = self:GetRawMaterial()
|
||||
mat:SetVector(key, val)
|
||||
if info.recompute then mat:Recompute() end
|
||||
end
|
||||
elseif info.type == "vec4" then
|
||||
-- need vec4 type
|
||||
PART["Set" .. property_name] = function(self, val)
|
||||
|
||||
local x,y,z,w
|
||||
if isstring(val) then
|
||||
x,y,z,w = unpack(val:Split(" "))
|
||||
x = tonumber(x) or 0
|
||||
y = tonumber(y) or 0
|
||||
z = tonumber(z) or 0
|
||||
w = tonumber(w) or 0
|
||||
elseif isvector(val) then
|
||||
x,y,z = val.x, val.y, val.z
|
||||
w = 0
|
||||
else
|
||||
x, y, z, w = 0, 0, 0, 0
|
||||
end
|
||||
|
||||
self[property_name] = ("%f %f %f %f"):format(x, y, z, w)
|
||||
local mat = self:GetRawMaterial()
|
||||
mat:SetString(key, ("[%f %f %f %f]"):format(x,y,z,w))
|
||||
|
||||
if info.recompute then mat:Recompute() end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetRawMaterial()
|
||||
if not self.Materialm then
|
||||
self.material_name = tostring({})
|
||||
local mat = pac.CreateMaterial(self.material_name, shader_name, {})
|
||||
self.Materialm = mat
|
||||
|
||||
for k,v in pairs(self:GetVars()) do
|
||||
if PART.ShaderParams[k] and PART.ShaderParams[k].default ~= nil then
|
||||
self["Set" .. k](self, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
return self.Materialm
|
||||
end
|
||||
|
||||
function PART:OnParent(parent)
|
||||
update_submaterial(self)
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
update_submaterial(self, true)
|
||||
end
|
||||
|
||||
function PART:OnUnParent(parent)
|
||||
update_submaterial(self, true, parent)
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
update_submaterial(self, true)
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
update_submaterial(self)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
end
|
||||
909
lua/pac3/core/client/parts/model.lua
Normal file
909
lua/pac3/core/client/parts/model.lua
Normal file
@@ -0,0 +1,909 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
CreateConVar( "pac_model_max_scales", "10000", FCVAR_ARCHIVE, "Maximum scales model can have")
|
||||
|
||||
|
||||
|
||||
|
||||
local pac = pac
|
||||
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_CullMode = render.CullMode
|
||||
local MATERIAL_CULLMODE_CW = MATERIAL_CULLMODE_CW
|
||||
local MATERIAL_CULLMODE_CCW = MATERIAL_CULLMODE_CCW
|
||||
local render_MaterialOverride = render.ModelMaterialOverride
|
||||
local cam_PushModelMatrix = cam.PushModelMatrix
|
||||
local cam_PopModelMatrix = cam.PopModelMatrix
|
||||
local Vector = Vector
|
||||
local EF_BONEMERGE = EF_BONEMERGE
|
||||
local NULL = NULL
|
||||
local Color = Color
|
||||
local Matrix = Matrix
|
||||
local vector_origin = vector_origin
|
||||
local render = render
|
||||
local cam = cam
|
||||
local surface = surface
|
||||
local render_MaterialOverrideByIndex = render.MaterialOverrideByIndex
|
||||
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "model"
|
||||
PART.ClassName = "model2"
|
||||
PART.Category = "model"
|
||||
PART.ManualDraw = true
|
||||
PART.HandleModifiersManually = true
|
||||
PART.Icon = 'icon16/shape_square.png'
|
||||
PART.is_model_part = true
|
||||
PART.ProperColorRange = true
|
||||
PART.Group = 'model'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:SetPropertyGroup("generic")
|
||||
:PropertyOrder("Name")
|
||||
:PropertyOrder("Hide")
|
||||
:PropertyOrder("ParentName")
|
||||
:GetSet("Model", "", {editor_panel = "model"})
|
||||
:GetSet("ForceObjUrl", false)
|
||||
|
||||
:SetPropertyGroup("orientation")
|
||||
:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
:GetSet("Scale", Vector(1,1,1))
|
||||
:GetSet("BoneMerge", false)
|
||||
:GetSet("LegacyTransform", false)
|
||||
|
||||
:SetPropertyGroup("appearance")
|
||||
:GetSet("Color", Vector(1, 1, 1), {editor_panel = "color2"})
|
||||
:GetSet("Brightness", 1)
|
||||
:GetSet("NoLighting", false)
|
||||
:GetSet("NoCulling", false)
|
||||
:GetSet("Invert", false)
|
||||
:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
:GetSet("ModelModifiers", "", {hidden = true})
|
||||
:GetSet("Material", "", {editor_panel = "material"})
|
||||
:GetSet("Materials", "", {hidden = true})
|
||||
:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.Clamp(tonumber(num), 0, pace.current_part:GetOwner():SkinCount())) end})
|
||||
:GetSet("LevelOfDetail", 0, {editor_clamp = {-1, 8}, editor_round = true})
|
||||
:GetSetPart("EyeTarget")
|
||||
|
||||
:EndStorableVars()
|
||||
|
||||
PART.Owner = NULL
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName(("/" .. self:GetModel()):match(".+/(.-)%."))
|
||||
|
||||
return str and str:gsub("%d", "") or "error"
|
||||
end
|
||||
|
||||
function PART:GetDynamicProperties()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() or not ent:GetBodyGroups() then return end
|
||||
|
||||
local tbl = {}
|
||||
|
||||
if ent:SkinCount() and ent:SkinCount() > 1 then
|
||||
tbl.skin = {
|
||||
key = "skin",
|
||||
set = function(val)
|
||||
local tbl = self:ModelModifiersToTable(self:GetModelModifiers())
|
||||
tbl.skin = val
|
||||
self:SetModelModifiers(self:ModelModifiersToString(tbl))
|
||||
end,
|
||||
get = function()
|
||||
return self:ModelModifiersToTable(self:GetModelModifiers()).skin
|
||||
end,
|
||||
udata = {editor_onchange = function(self, num) return math.Clamp(math.Round(num), 0, ent:SkinCount() - 1) end},
|
||||
}
|
||||
end
|
||||
|
||||
for _, info in ipairs(ent:GetBodyGroups()) do
|
||||
if info.num > 1 then
|
||||
tbl[info.name] = {
|
||||
key = info.name,
|
||||
set = function(val)
|
||||
local tbl = self:ModelModifiersToTable(self:GetModelModifiers())
|
||||
tbl[info.name] = val
|
||||
self:SetModelModifiers(self:ModelModifiersToString(tbl))
|
||||
end,
|
||||
get = function()
|
||||
return self:ModelModifiersToTable(self:GetModelModifiers())[info.name] or 0
|
||||
end,
|
||||
udata = {editor_onchange = function(self, num) return math.Clamp(math.Round(num), 0, info.num - 1) end, group = "bodygroups"},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
if ent:GetMaterials() and #ent:GetMaterials() > 1 then
|
||||
for i, name in ipairs(ent:GetMaterials()) do
|
||||
name = name:match(".+/(.+)") or name
|
||||
tbl[name] = {
|
||||
key = name,
|
||||
get = function()
|
||||
local tbl = self.Materials:Split(";")
|
||||
return tbl[i] or ""
|
||||
end,
|
||||
set = function(val)
|
||||
local tbl = self.Materials:Split(";")
|
||||
tbl[i] = val
|
||||
|
||||
for i, name in ipairs(ent:GetMaterials()) do
|
||||
tbl[i] = tbl[i] or ""
|
||||
end
|
||||
|
||||
self:SetMaterials(table.concat(tbl, ";"))
|
||||
end,
|
||||
udata = {editor_panel = "material", editor_friendly = name, group = "sub materials"},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
function PART:SetLevelOfDetail(val)
|
||||
self.LevelOfDetail = val
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
ent:SetLOD(val)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSkin(var)
|
||||
self.Skin = var
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner:SetSkin(var)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:ModelModifiersToTable(str)
|
||||
if str == "" or (not str:find(";", nil, true) and not str:find("=", nil, true)) then return {} end
|
||||
|
||||
local tbl = {}
|
||||
for _, data in ipairs(str:Split(";")) do
|
||||
local key, val = data:match("(.+)=(.+)")
|
||||
if key then
|
||||
key = key:Trim()
|
||||
val = tonumber(val:Trim())
|
||||
|
||||
tbl[key] = val
|
||||
end
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
function PART:ModelModifiersToString(tbl)
|
||||
local str = ""
|
||||
for k,v in pairs(tbl) do
|
||||
str = str .. k .. "=" .. v .. ";"
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
function PART:SetModelModifiers(str)
|
||||
self.ModelModifiers = str
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
local tbl = self:ModelModifiersToTable(str)
|
||||
|
||||
if tbl.skin then
|
||||
self:SetSkin(tbl.skin)
|
||||
tbl.skin = nil
|
||||
end
|
||||
|
||||
if not owner:GetBodyGroups() then return end
|
||||
|
||||
self.draw_bodygroups = {}
|
||||
|
||||
for i, info in ipairs(owner:GetBodyGroups()) do
|
||||
local val = tbl[info.name]
|
||||
if val then
|
||||
table.insert(self.draw_bodygroups, {info.id, val})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterial(str)
|
||||
self.Material = str
|
||||
|
||||
if str == "" then
|
||||
if self.material_override_self then
|
||||
self.material_override_self[0] = nil
|
||||
end
|
||||
else
|
||||
self.material_override_self = self.material_override_self or {}
|
||||
|
||||
if not pac.Handleurltex(self, str, function(mat)
|
||||
self.material_override_self = self.material_override_self or {}
|
||||
self.material_override_self[0] = mat
|
||||
end) then
|
||||
self.material_override_self[0] = pac.Material(str, self)
|
||||
end
|
||||
end
|
||||
|
||||
if self.material_override_self and not next(self.material_override_self) then
|
||||
self.material_override_self = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterials(str)
|
||||
self.Materials = str
|
||||
|
||||
local materials = self:GetOwner():IsValid() and self:GetOwner():GetMaterials()
|
||||
|
||||
if not materials then return end
|
||||
|
||||
self.material_count = #materials
|
||||
|
||||
self.material_override_self = self.material_override_self or {}
|
||||
|
||||
local tbl = str:Split(";")
|
||||
|
||||
for i = 1, #materials do
|
||||
local path = tbl[i]
|
||||
|
||||
if path and path ~= "" then
|
||||
if not pac.Handleurltex(self, path, function(mat)
|
||||
self.material_override_self = self.material_override_self or {}
|
||||
self.material_override_self[i] = mat
|
||||
end) then
|
||||
self.material_override_self[i] = pac.Material(path, self)
|
||||
end
|
||||
else
|
||||
self.material_override_self[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if not next(self.material_override_self) then
|
||||
self.material_override_self = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:Reset()
|
||||
self:Initialize()
|
||||
for _, key in pairs(self:GetStorableVars()) do
|
||||
if PART[key] then
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
self.cached_dynamic_props = nil
|
||||
end
|
||||
|
||||
function PART:OnBecomePhysics()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
ent:PhysicsInit(SOLID_NONE)
|
||||
ent:SetMoveType(MOVETYPE_NONE)
|
||||
ent:SetNoDraw(true)
|
||||
ent.RenderOverride = nil
|
||||
|
||||
self.skip_orient = false
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self.Owner = pac.CreateEntity(self:GetModel())
|
||||
self.Owner:SetNoDraw(true)
|
||||
self.Owner.PACPart = self
|
||||
self.material_count = 0
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local owner = self:GetParentOwner()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and owner:IsValid() and owner ~= ent then
|
||||
ent:SetPos(owner:EyePos())
|
||||
ent:SetLegacyTransform(self.LegacyTransform)
|
||||
self:SetBone(self:GetBone())
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if not self.loading then
|
||||
SafeRemoveEntityDelayed(self.Owner,0.1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
self:CheckBoneMerge()
|
||||
end
|
||||
|
||||
function PART:BindMaterials(ent)
|
||||
local materials = self.material_override_self or self.material_override
|
||||
local material_bound = false
|
||||
|
||||
if self.material_override_self then
|
||||
if materials[0] then
|
||||
render_MaterialOverride(materials[0])
|
||||
material_bound = true
|
||||
end
|
||||
|
||||
for i = 1, self.material_count do
|
||||
local mat = materials[i]
|
||||
|
||||
if mat then
|
||||
render_MaterialOverrideByIndex(i-1, mat)
|
||||
else
|
||||
render_MaterialOverrideByIndex(i-1, nil)
|
||||
end
|
||||
end
|
||||
elseif self.material_override then
|
||||
if materials[0] and materials[0][1] then
|
||||
render_MaterialOverride(materials[0][1]:GetRawMaterial())
|
||||
material_bound = true
|
||||
end
|
||||
|
||||
for i = 1, self.material_count do
|
||||
local stack = materials[i]
|
||||
if stack then
|
||||
local mat = stack[1]
|
||||
|
||||
if mat then
|
||||
render_MaterialOverrideByIndex(i-1, mat:GetRawMaterial())
|
||||
else
|
||||
render_MaterialOverrideByIndex(i-1, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.BoneMerge and not material_bound then
|
||||
render_MaterialOverride()
|
||||
end
|
||||
|
||||
return material_bound
|
||||
end
|
||||
|
||||
function PART:PreEntityDraw(ent, pos, ang)
|
||||
if not ent:IsPlayer() and pos and ang then
|
||||
if not self.skip_orient then
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
self:ModifiersPreEvent("OnDraw")
|
||||
|
||||
local r, g, b = self.Color.r, self.Color.g, self.Color.b
|
||||
local brightness = self.Brightness
|
||||
|
||||
-- render.SetColorModulation and render.SetAlpha set the material $color and $alpha.
|
||||
render_SetColorModulation(r*brightness, g*brightness, b*brightness)
|
||||
if not pac.drawing_motionblur_alpha then
|
||||
render_SetBlend(self.Alpha)
|
||||
end
|
||||
|
||||
if self.NoLighting then
|
||||
render_SuppressEngineLighting(true)
|
||||
end
|
||||
end
|
||||
|
||||
if self.draw_bodygroups then
|
||||
for _, v in ipairs(self.draw_bodygroups) do
|
||||
ent:SetBodygroup(v[1], v[2])
|
||||
end
|
||||
end
|
||||
|
||||
if self.EyeTarget:IsValid() and self.EyeTarget.GetWorldPosition then
|
||||
ent:SetEyeTarget(self.EyeTarget:GetWorldPosition())
|
||||
ent.pac_modified_eyetarget = true
|
||||
elseif ent.pac_modified_eyetarget then
|
||||
ent:SetEyeTarget(vector_origin)
|
||||
ent.pac_modified_eyetarget = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PostEntityDraw(ent, pos, ang)
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
self:ModifiersPostEvent("OnDraw")
|
||||
|
||||
if self.NoLighting then
|
||||
render_SuppressEngineLighting(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then
|
||||
self:Reset()
|
||||
ent = self:GetOwner()
|
||||
end
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
if self.loading then
|
||||
self:DrawLoadingText(ent, pos)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
self:PreEntityDraw(ent, pos, ang)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
self:PostEntityDraw(ent, pos, ang)
|
||||
|
||||
pac.ResetBones(ent)
|
||||
end
|
||||
|
||||
|
||||
local matrix = Matrix()
|
||||
local IDENT_SCALE = Vector(1,1,1)
|
||||
local _self, _ent, _pos, _ang
|
||||
|
||||
local function ent_draw_model(self, ent, pos, ang)
|
||||
if self.obj_mesh then
|
||||
ent:SetModelScale(0,0)
|
||||
ent:DrawModel()
|
||||
|
||||
matrix:Identity()
|
||||
matrix:SetAngles(ang)
|
||||
matrix:SetTranslation(pos)
|
||||
matrix:SetScale(self.Scale * self.Size)
|
||||
|
||||
cam_PushModelMatrix(matrix)
|
||||
self.obj_mesh:Draw()
|
||||
cam_PopModelMatrix()
|
||||
else
|
||||
if ent.needs_setupbones_from_legacy_bone_parts then
|
||||
pac.SetupBones(ent)
|
||||
ent.needs_setupbones_from_legacy_bone_parts = nil
|
||||
end
|
||||
ent:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
local function protected_ent_draw_model()
|
||||
ent_draw_model(_self, _ent, _pos, _ang)
|
||||
end
|
||||
|
||||
function PART:DrawModel(ent, pos, ang)
|
||||
if self.loading then
|
||||
self:DrawLoadingText(ent, pos)
|
||||
end
|
||||
|
||||
if self.Alpha == 0 or self.Size == 0 then return end
|
||||
if self.loading and not self.obj_mesh then return end
|
||||
|
||||
if self.NoCulling or self.Invert then
|
||||
render_CullMode(MATERIAL_CULLMODE_CW)
|
||||
end
|
||||
|
||||
local material_bound = false
|
||||
|
||||
material_bound = self:BindMaterials(ent) or material_bound
|
||||
|
||||
ent.pac_drawing_model = true
|
||||
ent_draw_model(self, ent, pos, ang)
|
||||
ent.pac_drawing_model = false
|
||||
|
||||
_self, _ent, _pos, _ang = self, ent, pos, ang
|
||||
|
||||
if self.ClassName ~= "entity2" then
|
||||
render.PushFlashlightMode(true)
|
||||
|
||||
material_bound = self:BindMaterials(ent) or material_bound
|
||||
ent.pac_drawing_model = true
|
||||
ProtectedCall(protected_ent_draw_model)
|
||||
ent.pac_drawing_model = false
|
||||
|
||||
render.PopFlashlightMode()
|
||||
end
|
||||
|
||||
if self.NoCulling then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
material_bound = self:BindMaterials(ent) or material_bound
|
||||
ProtectedCall(protected_ent_draw_model)
|
||||
elseif self.Invert then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
end
|
||||
|
||||
-- need to unbind mateiral
|
||||
if material_bound then
|
||||
render_MaterialOverride()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:DrawLoadingText(ent, pos)
|
||||
cam.Start2D()
|
||||
cam.IgnoreZ(true)
|
||||
local pos2d = pos:ToScreen()
|
||||
|
||||
surface.SetFont("DermaDefault")
|
||||
|
||||
if self.errored then
|
||||
surface.SetTextColor(255, 0, 0, 255)
|
||||
local str = self.loading:match("^(.-):\n") or self.loading:match("^(.-)\n") or self.loading:sub(1, 100)
|
||||
local w, h = surface.GetTextSize(str)
|
||||
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
||||
surface.DrawText(str)
|
||||
self:SetError(str)
|
||||
else
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
local str = self.loading .. string.rep(".", pac.RealTime * 3 % 3)
|
||||
local w, h = surface.GetTextSize(self.loading .. "...")
|
||||
|
||||
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
||||
surface.DrawText(str)
|
||||
self:SetError()
|
||||
end
|
||||
cam.IgnoreZ(false)
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
local ALLOW_TO_MDL = CreateConVar('pac_allow_mdl', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs')
|
||||
|
||||
function PART:RefreshModel()
|
||||
if self.refreshing_model then return end
|
||||
|
||||
self.refreshing_model = true
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
pac.ResetBoneCache(ent)
|
||||
end
|
||||
|
||||
self.cached_dynamic_props = nil
|
||||
|
||||
self:SetModelModifiers(self:GetModelModifiers())
|
||||
self:SetMaterials(self:GetMaterials())
|
||||
self:SetSize(self:GetSize())
|
||||
self:SetScale(self:GetScale())
|
||||
self:SetSkin(self:GetSkin())
|
||||
self:SetLevelOfDetail(self:GetLevelOfDetail())
|
||||
|
||||
if not self:IsHidden() and not self:IsDrawHidden() then
|
||||
-- notify children about model change
|
||||
self:ShowFromRendering()
|
||||
end
|
||||
|
||||
self.refreshing_model = false
|
||||
end
|
||||
|
||||
function PART:RealSetModel(path)
|
||||
self:GetOwner():SetModel(path)
|
||||
self:RefreshModel()
|
||||
end
|
||||
|
||||
function PART:SetForceObjUrl(value)
|
||||
self.ForceObjUrl = value
|
||||
self:ProcessModelChange()
|
||||
end
|
||||
|
||||
local function RealDrawModel(self, ent, pos, ang)
|
||||
if self.Mesh then
|
||||
ent:SetModelScale(0,0)
|
||||
ent:DrawModel()
|
||||
|
||||
local matrix = Matrix()
|
||||
|
||||
matrix:SetAngles(ang)
|
||||
matrix:SetTranslation(pos)
|
||||
|
||||
if ent.pac_model_scale then
|
||||
matrix:Scale(ent.pac_model_scale)
|
||||
else
|
||||
matrix:Scale(self.Scale * self.Size)
|
||||
end
|
||||
|
||||
cam_PushModelMatrix(matrix)
|
||||
self.Mesh:Draw()
|
||||
cam_PopModelMatrix()
|
||||
else
|
||||
ent:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:ProcessModelChange()
|
||||
local owner = self:GetOwner()
|
||||
if not owner:IsValid() then return end
|
||||
local path = self.Model
|
||||
|
||||
if path:find("://", nil, true) then
|
||||
if path:StartWith("objhttp") or path:StartWith("obj:http") or path:match("%.obj%p?") or self.ForceObjUrl then
|
||||
path = path:gsub("^objhttp","http"):gsub("^obj:http","http")
|
||||
self.loading = "downloading obj"
|
||||
|
||||
pac.urlobj.GetObjFromURL(path, false, false,
|
||||
function(meshes, err)
|
||||
|
||||
local function set_mesh(part, mesh)
|
||||
local owner = part:GetOwner()
|
||||
part.obj_mesh = mesh
|
||||
pac.ResetBoneCache(owner)
|
||||
|
||||
if not part.Materialm then
|
||||
part.Materialm = Material("error")
|
||||
end
|
||||
|
||||
function owner.pacDrawModel(ent, simple)
|
||||
if simple then
|
||||
RealDrawModel(part, ent, ent:GetPos(), ent:GetAngles())
|
||||
else
|
||||
part:ModifiersPreEvent("OnDraw")
|
||||
part:DrawModel(ent, ent:GetPos(), ent:GetAngles())
|
||||
part:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
end
|
||||
|
||||
owner:SetRenderBounds(Vector(1, 1, 1) * -300, Vector(1, 1, 1) * 300)
|
||||
end
|
||||
|
||||
if not self:IsValid() then return end
|
||||
|
||||
self.loading = false
|
||||
|
||||
if not meshes and err then
|
||||
owner:SetModel("models/error.mdl")
|
||||
self.obj_mesh = nil
|
||||
return
|
||||
end
|
||||
|
||||
if table.Count(meshes) == 1 then
|
||||
set_mesh(self, select(2, next(meshes)))
|
||||
else
|
||||
for key, mesh in pairs(meshes) do
|
||||
local part = pac.CreatePart("model", self:GetOwnerName())
|
||||
part:SetName(key)
|
||||
part:SetParent(self)
|
||||
part:SetMaterial(self:GetMaterial())
|
||||
set_mesh(part, mesh)
|
||||
end
|
||||
|
||||
self:SetAlpha(0)
|
||||
end
|
||||
end,
|
||||
|
||||
function(finished, statusMessage)
|
||||
if finished then
|
||||
self.loading = nil
|
||||
else
|
||||
self.loading = statusMessage
|
||||
end
|
||||
end
|
||||
)
|
||||
else
|
||||
local status, reason = hook.Run('PAC3AllowMDLDownload', self:GetPlayerOwner(), self, path)
|
||||
|
||||
if ALLOW_TO_MDL:GetBool() and status ~= false then
|
||||
self.loading = "downloading mdl zip"
|
||||
pac.DownloadMDL(path, function(mdl_path)
|
||||
self.loading = nil
|
||||
self.errored = nil
|
||||
|
||||
if self.ClassName == "entity2" then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", self:GetOwner(), path)
|
||||
end
|
||||
|
||||
self:RealSetModel(mdl_path)
|
||||
|
||||
end, function(err)
|
||||
|
||||
if pace and pace.current_part == self and not IsValid(pace.BusyWithProperties) then
|
||||
pace.MessagePrompt(err, "HTTP Request Failed for " .. path, "OK")
|
||||
else
|
||||
pac.Message(Color(0, 255, 0), "[model] ", Color(255, 255, 255), "HTTP Request Failed for " .. path .. " - " .. err)
|
||||
end
|
||||
|
||||
self.loading = err
|
||||
self.errored = true
|
||||
self:RealSetModel("models/error.mdl")
|
||||
end, self:GetPlayerOwner())
|
||||
else
|
||||
local msg = reason or "mdl's are not allowed"
|
||||
self.loading = msg
|
||||
self:SetError(msg)
|
||||
self:RealSetModel("models/error.mdl")
|
||||
pac.Message(self, msg)
|
||||
end
|
||||
end
|
||||
elseif path ~= "" then
|
||||
if self.ClassName == "entity2" then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", owner, path)
|
||||
end
|
||||
|
||||
self:RealSetModel(path)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetModel(path)
|
||||
self.Model = path
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
self.old_model = path
|
||||
self:ProcessModelChange()
|
||||
end
|
||||
|
||||
local NORMAL = Vector(1,1,1)
|
||||
|
||||
function PART:CheckScale()
|
||||
local owner = self:GetOwner()
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
-- RenderMultiply doesn't work with this..
|
||||
if self.BoneMerge and owner:GetBoneCount() and owner:GetBoneCount() > 1 then
|
||||
if self.Scale * self.Size ~= NORMAL then
|
||||
if not self.requires_bone_model_scale then
|
||||
self.requires_bone_model_scale = true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetAlternativeScaling(b)
|
||||
self.AlternativeScaling = b
|
||||
self:SetScale(self.Scale)
|
||||
end
|
||||
|
||||
function PART:SetScale(vec)
|
||||
local max_scale = GetConVar("pac_model_max_scales"):GetFloat()
|
||||
local largest_scale = math.max(math.abs(vec.x), math.abs(vec.y), math.abs(vec.z))
|
||||
|
||||
if vec and max_scale > 0 and (LocalPlayer() ~= self:GetPlayerOwner()) then --clamp for other players if they have pac_model_max_scales convar more than 0
|
||||
vec = Vector(math.Clamp(vec.x, -max_scale, max_scale), math.Clamp(vec.y, -max_scale, max_scale), math.Clamp(vec.z, -max_scale, max_scale))
|
||||
end
|
||||
if largest_scale > 10000 then --warn about the default max scale
|
||||
self:SetError("Scale is being limited due to having an excessive component. Default maximum values are 10000")
|
||||
else self:SetError() end --if ok, clear the warning
|
||||
vec = vec or Vector(1,1,1)
|
||||
|
||||
self.Scale = vec
|
||||
|
||||
if not self:CheckScale() then
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
end
|
||||
|
||||
local vec_one = Vector(1,1,1)
|
||||
|
||||
function PART:ApplyMatrix()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
local mat = Matrix()
|
||||
|
||||
if self.ClassName ~= "model2" then
|
||||
mat:Translate(self.Position + self.PositionOffset)
|
||||
mat:Rotate(self.Angles + self.AngleOffset)
|
||||
end
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "size", ent, self.Size, {
|
||||
StandingHullHeight = self.StandingHullHeight,
|
||||
CrouchingHullHeight = self.CrouchingHullHeight,
|
||||
HullWidth = self.HullWidth,
|
||||
})
|
||||
|
||||
if self.Size == 1 and self.Scale == vec_one then
|
||||
if self.InverseKinematics then
|
||||
if ent:GetModelScale() ~= 1 then
|
||||
ent:SetModelScale(1, 0)
|
||||
end
|
||||
ent:SetIK(true)
|
||||
else
|
||||
ent:SetModelScale(1.000001, 0)
|
||||
ent:SetIK(false)
|
||||
end
|
||||
end
|
||||
|
||||
mat:Scale(self.Scale)
|
||||
else
|
||||
mat:Scale(self.Scale * self.Size)
|
||||
end
|
||||
|
||||
ent.pac_model_scale = mat:GetScale()
|
||||
|
||||
if mat:IsIdentity() then
|
||||
ent:DisableMatrix("RenderMultiply")
|
||||
else
|
||||
ent:EnableMatrix("RenderMultiply", mat)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSize(var)
|
||||
var = var or 1
|
||||
|
||||
self.Size = var
|
||||
|
||||
if not self:CheckScale() then
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:CheckBoneMerge()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent == pac.LocalHands or ent == pac.LocalViewModel then return end
|
||||
|
||||
if self.skip_orient then return end
|
||||
|
||||
if ent:IsValid() and not ent:IsPlayer() and ent:GetModel() then
|
||||
if self.BoneMerge then
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if ent:GetParent() ~= owner then
|
||||
ent:SetParent(owner)
|
||||
|
||||
if not ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:AddEffects(EF_BONEMERGE)
|
||||
owner.pac_bonemerged = owner.pac_bonemerged or {}
|
||||
table.insert(owner.pac_bonemerged, ent)
|
||||
ent.RenderOverride = function()
|
||||
ent.pac_drawing_model = true
|
||||
ent:DrawModel()
|
||||
ent.pac_drawing_model = false
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if ent:GetParent():IsValid() then
|
||||
local owner = ent:GetParent()
|
||||
ent:SetParent(NULL)
|
||||
|
||||
if ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:RemoveEffects(EF_BONEMERGE)
|
||||
ent.RenderOverride = nil
|
||||
|
||||
if owner:IsValid() then
|
||||
owner.pac_bonemerged = owner.pac_bonemerged or {}
|
||||
for i, v in ipairs(owner.pac_bonemerged) do
|
||||
if v == ent then
|
||||
table.remove(owner.pac_bonemerged, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
if self.AlternativeScaling then return end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if not ent:IsValid() or not owner:IsValid() or not ent:GetBoneCount() or ent:GetBoneCount() < 1 then return end
|
||||
|
||||
if self.requires_bone_model_scale then
|
||||
local scale = self.Scale * self.Size
|
||||
|
||||
for i = 0, ent:GetBoneCount() - 1 do
|
||||
if i == 0 then
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * Vector(scale.x ^ 0.25, scale.y ^ 0.25, scale.z ^ 0.25))
|
||||
else
|
||||
ent:ManipulateBonePosition(i, ent:GetManipulateBonePosition(i) + Vector((scale.x-1) ^ 4, 0, 0))
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * scale)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
include("model/entity.lua")
|
||||
include("model/weapon.lua")
|
||||
262
lua/pac3/core/client/parts/model/entity.lua
Normal file
262
lua/pac3/core/client/parts/model/entity.lua
Normal file
@@ -0,0 +1,262 @@
|
||||
--[[
|
||||
| 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 pac = pac
|
||||
local Vector = Vector
|
||||
local Angle = Angle
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("model2")
|
||||
|
||||
PART.FriendlyName = "entity"
|
||||
PART.ClassName = "entity2"
|
||||
PART.Category = "entity"
|
||||
PART.ManualDraw = true
|
||||
PART.HandleModifiersManually = true
|
||||
PART.Icon = 'icon16/brick.png'
|
||||
PART.Group = "entity"
|
||||
PART.is_entity_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:SetPropertyGroup("generic")
|
||||
:PropertyOrder("Name")
|
||||
:PropertyOrder("Hide")
|
||||
:PropertyOrder("ParentName")
|
||||
:SetPropertyGroup("appearance")
|
||||
:GetSet("NoDraw", false)
|
||||
:GetSet("DrawShadow", true)
|
||||
:GetSet("InverseKinematics", true)
|
||||
|
||||
:SetPropertyGroup("hull")
|
||||
:GetSet("StandingHullHeight", 72, {editor_panel = "hull"})
|
||||
:GetSet("CrouchingHullHeight", 36, {editor_panel = "hull", crouch = true})
|
||||
:GetSet("HullWidth", 32, {editor_panel = "hull"})
|
||||
:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("BoneMerge")
|
||||
BUILDER:RemoveProperty("Bone")
|
||||
BUILDER:RemoveProperty("EyeAngles")
|
||||
BUILDER:RemoveProperty("AimPartName")
|
||||
BUILDER:RemoveProperty("ForceObjUrl")
|
||||
|
||||
function PART:SetDrawShadow(b)
|
||||
self.DrawShadow = b
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent:DrawShadow(b)
|
||||
ent:MarkShadowAsDirty()
|
||||
end
|
||||
|
||||
function PART:SetStandingHullHeight(val)
|
||||
self.StandingHullHeight = val
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
function PART:SetCrouchingHullHeight(val)
|
||||
self.CrouchingHullHeight = val
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
function PART:SetHullWidth(val)
|
||||
self.HullWidth = val
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName(("/" .. self:GetModel()):match(".+/(.-)%.")) or self:GetModel()
|
||||
|
||||
local class_name = "NULL"
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
class_name = ent:GetClass()
|
||||
end
|
||||
|
||||
return (str and str:gsub("%d", "") or "error") .. " " .. class_name .. " model"
|
||||
end
|
||||
|
||||
function PART:SetPosition(pos)
|
||||
self.Position = pos
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:SetAngles(ang)
|
||||
self.Angles = ang
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:SetPositionOffset(pos)
|
||||
self.PositionOffset = pos
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:SetAngleOffset(ang)
|
||||
self.AngleOffset = ang
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local ent = self:GetParentOwner()
|
||||
if not ent:IsValid() then return Vector(), Angle() end
|
||||
local ang = ent:GetAngles()
|
||||
if ent:IsPlayer() then
|
||||
ang.p = 0
|
||||
end
|
||||
return ent:GetPos(), ang
|
||||
end
|
||||
|
||||
-- this also implicitly overrides parent init to not create a custom owner
|
||||
function PART:Initialize()
|
||||
self.material_count = 0
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local ent = self:GetOwner()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:PreEntityDraw(ent, pos, ang)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
self:PostEntityDraw(ent, pos, ang)
|
||||
end
|
||||
|
||||
local temp_mat = Material( "models/error/new light1" )
|
||||
|
||||
function PART:RenderOverride(ent)
|
||||
-- if the draw call is not from pac don't bother
|
||||
if not ent.pac_drawing_model then
|
||||
if not ent.pac_is_drawing and ent ~= pac.LocalPlayer and ent.pac_ragdoll_owner ~= pac.LocalPlayer then
|
||||
ent.RenderOverride = nil
|
||||
ent:DisableMatrix("RenderMultiply")
|
||||
ent:SetSkin(0)
|
||||
ent:SetLOD(-1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self:IsValid() and self:GetParentOwner():IsValid() then
|
||||
if ent.pac_bonemerged then
|
||||
for _, e in ipairs(ent.pac_bonemerged) do
|
||||
if e.pac_drawing_model then return end
|
||||
end
|
||||
end
|
||||
|
||||
-- so eyes work
|
||||
if self.NoDraw then
|
||||
if ent == pac.LocalViewModel or ent == pac.LocalHands then return end
|
||||
render.SetBlend(0)
|
||||
render.ModelMaterialOverride(temp_mat)
|
||||
ent.pac_drawing_model = true
|
||||
ent:DrawModel()
|
||||
ent.pac_drawing_model = false
|
||||
render.SetBlend(1)
|
||||
render.ModelMaterialOverride()
|
||||
return
|
||||
end
|
||||
|
||||
ent:SetSkin(self:GetSkin())
|
||||
self:Draw(self.Translucent and "translucent" or "opaque")
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
function ent.RenderOverride()
|
||||
if self:IsValid() then
|
||||
self:RenderOverride(ent)
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
|
||||
if not self.real_model then
|
||||
self.real_model = ent:GetModel()
|
||||
end
|
||||
|
||||
if not (self.old_model == self:GetModel()) or
|
||||
(pac.LocalHands:IsValid() and ent == pac.LocalHands
|
||||
and not (self.real_model == pac.LocalHands:GetModel())) then
|
||||
self.old_model = self:GetModel()
|
||||
self:SetModel(self:GetModel())
|
||||
end
|
||||
|
||||
self:SetDrawShadow(self:GetDrawShadow())
|
||||
self:RefreshModel()
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetParentOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.RenderOverride = nil
|
||||
ent:DisableMatrix("RenderMultiply")
|
||||
ent:SetSkin(0)
|
||||
ent:SetLOD(-1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:RealSetModel(path)
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent:SetModel(path)
|
||||
self.real_model = path
|
||||
self:RefreshModel()
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
local player_owner = self:GetPlayerOwner()
|
||||
|
||||
pac.emut.RestoreMutations(player_owner, "model", ent)
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
pac.emut.RestoreMutations(player_owner, "size", ent)
|
||||
end
|
||||
|
||||
ent:DisableMatrix("RenderMultiply")
|
||||
end
|
||||
|
||||
function PART:SetInverseKinematics(b)
|
||||
self.InverseKinematics = b
|
||||
|
||||
local ent = self:GetParentOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_enable_ik = b
|
||||
self:ApplyMatrix()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
self:CheckBoneMerge()
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
local model = ent:GetModel()
|
||||
local bone_count = ent:GetBoneCount()
|
||||
if
|
||||
self.last_model ~= model or
|
||||
self.last_bone_count ~= bone_count
|
||||
then
|
||||
self:RefreshModel()
|
||||
self.last_model = model
|
||||
self.last_bone_count = bone_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
171
lua/pac3/core/client/parts/model/weapon.lua
Normal file
171
lua/pac3/core/client/parts/model/weapon.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
--[[
|
||||
| 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 pac = pac
|
||||
local NULL = NULL
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("model2")
|
||||
|
||||
PART.ClassName = "weapon"
|
||||
PART.FriendlyName = "weapon"
|
||||
PART.Category = "entity"
|
||||
PART.ManualDraw = true
|
||||
PART.HandleModifiersManually = true
|
||||
PART.Icon = 'icon16/brick.png'
|
||||
PART.Group = "entity"
|
||||
PART.is_model_part = false
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:SetPropertyGroup("generic")
|
||||
:PropertyOrder("Name")
|
||||
:PropertyOrder("Hide")
|
||||
:PropertyOrder("ParentName")
|
||||
:GetSet("OverridePosition", false)
|
||||
:GetSet("Class", "all", {enums = function()
|
||||
local out = {
|
||||
["physgun"] = "weapon_physgun",
|
||||
["357"] = "weapon_357",
|
||||
["alyxgun"] = "weapon_alyxgun",
|
||||
["annabelle"] = "weapon_annabelle",
|
||||
["ar2"] = "weapon_ar2",
|
||||
["brickbat"] = "weapon_brickbat",
|
||||
["bugbait"] = "weapon_bugbait",
|
||||
["crossbow"] = "weapon_crossbow",
|
||||
["crowbar"] = "weapon_crowbar",
|
||||
["frag"] = "weapon_frag",
|
||||
["physcannon"] = "weapon_physcannon",
|
||||
["pistol"] = "weapon_pistol",
|
||||
["rpg"] = "weapon_rpg",
|
||||
["shotgun"] = "weapon_shotgun",
|
||||
["smg1"] = "weapon_smg1",
|
||||
["striderbuster"] = "weapon_striderbuster",
|
||||
["stunstick"] = "weapon_stunstick",
|
||||
}
|
||||
for _, tbl in pairs(weapons.GetList()) do
|
||||
if not tbl.ClassName:StartWith("ai_") then
|
||||
local friendly = tbl.ClassName:match("weapon_(.+)") or tbl.ClassName
|
||||
out[friendly] = tbl.ClassName
|
||||
end
|
||||
end
|
||||
return out
|
||||
end})
|
||||
:SetPropertyGroup("appearance")
|
||||
:GetSet("NoDraw", false)
|
||||
:GetSet("DrawShadow", true)
|
||||
:SetPropertyGroup("orientation")
|
||||
:GetSet("Bone", "right hand")
|
||||
:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Model")
|
||||
BUILDER:RemoveProperty("ForceObjUrl")
|
||||
|
||||
function PART:SetDrawShadow(b)
|
||||
self.DrawShadow = b
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
ent:DrawShadow(b)
|
||||
ent:MarkShadowAsDirty()
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
if self.Class ~= "all" then
|
||||
return self.Class
|
||||
end
|
||||
return self.ClassName
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self.material_count = 0
|
||||
end
|
||||
function PART:OnDraw()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
local old
|
||||
if self.OverridePosition then
|
||||
old = ent:GetParent()
|
||||
ent:SetParent(NULL)
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
pac.SetupBones(ent)
|
||||
end
|
||||
ent.pac_render = true
|
||||
|
||||
self:PreEntityDraw(ent, pos, ang)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
self:PostEntityDraw(ent, pos, ang)
|
||||
pac.ResetBones(ent)
|
||||
|
||||
if self.OverridePosition then
|
||||
ent:MarkShadowAsDirty()
|
||||
ent:SetParent(old)
|
||||
end
|
||||
ent.pac_render = nil
|
||||
end
|
||||
|
||||
PART.AlwaysThink = true
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
if ent:IsValid() and ent.GetActiveWeapon then
|
||||
local wep = ent:GetActiveWeapon()
|
||||
if wep:IsValid() then
|
||||
if wep ~= self.Owner then
|
||||
if self.Class == "all" or (self.Class:lower() == wep:GetClass():lower()) then
|
||||
self:OnHide()
|
||||
self.Owner = wep
|
||||
self:SetEventTrigger(self, false)
|
||||
wep.RenderOverride = function()
|
||||
if self:IsHiddenCached() then
|
||||
wep.RenderOverride = nil
|
||||
return
|
||||
end
|
||||
if wep.pac_render then
|
||||
if not self.NoDraw then
|
||||
if self.DrawShadow then
|
||||
wep:CreateShadow()
|
||||
end
|
||||
wep:DrawModel()
|
||||
end
|
||||
end
|
||||
end
|
||||
wep.pac_weapon_part = self
|
||||
self:SetDrawShadow(self:GetDrawShadow())
|
||||
else
|
||||
self:SetEventTrigger(self, true)
|
||||
self:OnHide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
self.Owner = NULL
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
|
||||
if ent:IsValid() and ent.GetActiveWeapon then
|
||||
for _, wep in pairs(ent:GetWeapons()) do
|
||||
if wep.pac_weapon_part == self then
|
||||
wep.RenderOverride = nil
|
||||
wep:SetParent(ent)
|
||||
end
|
||||
end
|
||||
self.Owner = NULL
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
108
lua/pac3/core/client/parts/motion_blur.lua
Normal file
108
lua/pac3/core/client/parts/motion_blur.lua
Normal file
@@ -0,0 +1,108 @@
|
||||
--[[
|
||||
| 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 render_SetBlend = render.SetBlend
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "motion_blur"
|
||||
PART.Group = 'modifiers'
|
||||
PART.Icon = 'icon16/shape_ungroup.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:GetSet("Bone", "none")
|
||||
:GetSet("Alpha", 0.5)
|
||||
:GetSet("BlurLength", 10)
|
||||
:GetSet("BlurSpacing", 0.1)
|
||||
:EndStorableVars()
|
||||
|
||||
|
||||
function PART:OnShow()
|
||||
if self.BlurLength > 0 then
|
||||
self.blur_history = {}
|
||||
self.blur_last_add = 0
|
||||
pac.drawing_motionblur_alpha = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:DrawBlur(pos, ang)
|
||||
local parent = self:GetParent()
|
||||
if not parent:IsValid() then return end
|
||||
local ent = parent:GetOwner()
|
||||
|
||||
if not parent.OnDraw then return end
|
||||
|
||||
self.blur_history = self.blur_history or {}
|
||||
|
||||
local blurSpacing = self.BlurSpacing
|
||||
|
||||
if not self.blur_last_add or blurSpacing == 0 or self.blur_last_add < pac.RealTime then
|
||||
|
||||
local bones = {}
|
||||
local i = 1
|
||||
for id = 0, ent:GetBoneCount() - 1 do
|
||||
local mat = ent:GetBoneMatrix(id)
|
||||
if mat then
|
||||
bones[i] = {id = id, matrix = mat}
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
table_insert(self.blur_history, {pos, ang, ent:GetCycle(), bones})
|
||||
self.blur_last_add = pac.RealTime + blurSpacing / 1000
|
||||
end
|
||||
|
||||
local prev_cycle = ent:GetCycle()
|
||||
|
||||
local blurHistoryLength = #self.blur_history
|
||||
for i = 1, blurHistoryLength do
|
||||
local pos, ang, cycle, bones = self.blur_history[i][1], self.blur_history[i][2], self.blur_history[i][3], self.blur_history[i][4]
|
||||
|
||||
local alpha = self.Alpha * (i / blurHistoryLength)
|
||||
render_SetBlend(alpha)
|
||||
|
||||
if ent then
|
||||
ent:SetCycle(cycle)
|
||||
|
||||
for _, data in ipairs(bones) do
|
||||
pcall(ent.SetBoneMatrix, ent, data.id, data.matrix)
|
||||
end
|
||||
end
|
||||
|
||||
pac.drawing_motionblur_alpha = alpha
|
||||
parent:OnDraw(ent, pos, ang)
|
||||
pac.drawing_motionblur_alpha = false
|
||||
|
||||
if ent then
|
||||
pac.SetupBones(ent)
|
||||
end
|
||||
end
|
||||
|
||||
ent:SetCycle(prev_cycle)
|
||||
|
||||
local maximumBlurHistoryLength = math.min(self.BlurLength, 20)
|
||||
while #self.blur_history >= maximumBlurHistoryLength do
|
||||
table_remove(self.blur_history, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if pac.drawing_motionblur_alpha then return end
|
||||
|
||||
if self.BlurLength > 0 then
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
self:DrawBlur(pos, ang)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
129
lua/pac3/core/client/parts/movement.lua
Normal file
129
lua/pac3/core/client/parts/movement.lua
Normal file
@@ -0,0 +1,129 @@
|
||||
--[[
|
||||
| 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 = "player_movement"
|
||||
PART.Group = "entity"
|
||||
PART.Icon = "icon16/user_go.png"
|
||||
|
||||
|
||||
local pac_movement_default = {}
|
||||
local update_these = {}
|
||||
|
||||
local function ADD(PART, name, default, ...)
|
||||
BUILDER:GetSet(name, default, ...)
|
||||
|
||||
pac_movement_default[name] = default
|
||||
|
||||
PART["Set" .. name] = function(self, val)
|
||||
self[name] = val
|
||||
|
||||
local ply = self:GetRootPart():GetOwner()
|
||||
|
||||
if ply == pac.LocalPlayer then
|
||||
|
||||
if self:IsHidden() then return end
|
||||
|
||||
local num = GetConVarNumber("pac_free_movement")
|
||||
if num == 1 or (num == -1 and hook.Run("PlayerNoClip", ply, true)) then
|
||||
ply.pac_movement = ply.pac_movement or table.Copy(pac_movement_default)
|
||||
|
||||
if ply.pac_movement[name] ~= val then
|
||||
net.Start("pac_modify_movement", true)
|
||||
net.WriteString(name)
|
||||
net.WriteType(val)
|
||||
net.SendToServer()
|
||||
end
|
||||
ply.pac_movement[name] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(update_these, function(s) PART["Set" .. name](s, PART["Get" .. name](s)) end)
|
||||
end
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
ADD(PART, "Noclip", false)
|
||||
ADD(PART, "Gravity", Vector(0, 0, -600))
|
||||
|
||||
BUILDER:SetPropertyGroup("movement")
|
||||
ADD(PART, "SprintSpeed", 400)
|
||||
ADD(PART, "RunSpeed", 200)
|
||||
ADD(PART, "WalkSpeed", 100)
|
||||
ADD(PART, "DuckSpeed", 25)
|
||||
|
||||
BUILDER:SetPropertyGroup("ground")
|
||||
ADD(PART, "JumpHeight", 200, {editor_clamp = {0, 10000}})
|
||||
ADD(PART, "MaxGroundSpeed", 750)
|
||||
ADD(PART, "StickToGround", true)
|
||||
ADD(PART, "GroundFriction", 0.12, {editor_clamp = {0, 1}, editor_sensitivity = 0.1})
|
||||
|
||||
BUILDER:SetPropertyGroup("air")
|
||||
ADD(PART, "AllowZVelocity", false)
|
||||
ADD(PART, "AirFriction", 0.01, {editor_clamp = {0, 1}, editor_sensitivity = 0.1})
|
||||
ADD(PART, "MaxAirSpeed", 1)
|
||||
|
||||
BUILDER:SetPropertyGroup("view angles")
|
||||
ADD(PART, "ReversePitch", false)
|
||||
ADD(PART, "UnlockPitch", false)
|
||||
ADD(PART, "VelocityToViewAngles", 0, {editor_clamp = {0, 1}, editor_sensitivity = 0.1})
|
||||
ADD(PART, "RollAmount", 0, {editor_sensitivity = 0.25})
|
||||
|
||||
BUILDER:SetPropertyGroup("fin")
|
||||
ADD(PART, "FinEfficiency", 0)
|
||||
ADD(PART, "FinLiftMode", "normal", {enums = {
|
||||
normal = "normal",
|
||||
none = "none",
|
||||
}})
|
||||
ADD(PART, "FinCline", false)
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
local str = self.ClassName
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:IsPlayer() then
|
||||
str = ent:Nick()
|
||||
else
|
||||
str = language.GetPhrase(ent:GetClass())
|
||||
end
|
||||
end
|
||||
|
||||
return str .. "'s movement"
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.last_movement_part = self:GetUniqueID()
|
||||
for i,v in ipairs(update_these) do
|
||||
v(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
|
||||
if ent == pac.LocalPlayer and ent.last_movement_part == self:GetUniqueID() then
|
||||
net.Start("pac_modify_movement", true)
|
||||
net.WriteString("disable")
|
||||
net.SendToServer()
|
||||
|
||||
ent.pac_movement = nil
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
375
lua/pac3/core/client/parts/particles.lua
Normal file
375
lua/pac3/core/client/parts/particles.lua
Normal file
@@ -0,0 +1,375 @@
|
||||
--[[
|
||||
| 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 cam_IgnoreZ = cam.IgnoreZ
|
||||
local vector_origin = vector_origin
|
||||
local FrameTime = FrameTime
|
||||
local angle_origin = Angle(0,0,0)
|
||||
local WorldToLocal = WorldToLocal
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "particles"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/water.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Follow", false)
|
||||
BUILDER:GetSet("Additive", false)
|
||||
BUILDER:GetSet("FireOnce", false)
|
||||
BUILDER:GetSet("FireDelay", 0.2)
|
||||
BUILDER:GetSet("NumberParticles", 1)
|
||||
BUILDER:GetSet("PositionSpread", 0)
|
||||
BUILDER:GetSet("PositionSpread2", Vector(0,0,0))
|
||||
BUILDER:GetSet("DieTime", 3)
|
||||
BUILDER:GetSet("StartSize", 2)
|
||||
BUILDER:GetSet("EndSize", 20)
|
||||
BUILDER:GetSet("StartLength", 0)
|
||||
BUILDER:GetSet("EndLength", 0)
|
||||
BUILDER:GetSet("ParticleAngle", Angle(0,0,0))
|
||||
BUILDER:GetSet("AddFrametimeLife", false)
|
||||
BUILDER:SetPropertyGroup("stick")
|
||||
BUILDER:GetSet("AlignToSurface", true)
|
||||
BUILDER:GetSet("StickToSurface", true)
|
||||
BUILDER:GetSet("StickLifetime", 2)
|
||||
BUILDER:GetSet("StickStartSize", 20)
|
||||
BUILDER:GetSet("StickEndSize", 0)
|
||||
BUILDER:GetSet("StickStartAlpha", 255)
|
||||
BUILDER:GetSet("StickEndAlpha", 0)
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Material", "effects/slime1")
|
||||
BUILDER:GetSet("StartAlpha", 255)
|
||||
BUILDER:GetSet("EndAlpha", 0)
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
BUILDER:GetSet("Color2", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Color1", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("RandomColor", false)
|
||||
BUILDER:GetSet("Lighting", true)
|
||||
BUILDER:GetSet("3D", false)
|
||||
BUILDER:GetSet("DoubleSided", true)
|
||||
BUILDER:GetSet("DrawManual", false)
|
||||
BUILDER:SetPropertyGroup("rotation")
|
||||
BUILDER:GetSet("ZeroAngle",true)
|
||||
BUILDER:GetSet("RandomRollSpeed", 0)
|
||||
BUILDER:GetSet("RollDelta", 0)
|
||||
BUILDER:GetSet("ParticleAngleVelocity", Vector(50, 50, 50))
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:SetPropertyGroup("movement")
|
||||
BUILDER:GetSet("Velocity", 250)
|
||||
BUILDER:GetSet("Spread", 0.1)
|
||||
BUILDER:GetSet("AirResistance", 5)
|
||||
BUILDER:GetSet("Bounce", 5)
|
||||
BUILDER:GetSet("Gravity", Vector(0,0, -50))
|
||||
BUILDER:GetSet("Collide", true)
|
||||
BUILDER:GetSet("Sliding", true)
|
||||
--BUILDER:GetSet("AddVelocityFromOwner", false)
|
||||
BUILDER:GetSet("OwnerVelocityMultiplier", 0)
|
||||
|
||||
|
||||
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
return pac.PrettifyName(("/".. self:GetMaterial()):match(".+/(.+)")) or "error"
|
||||
end
|
||||
|
||||
local function RemoveCallback(particle)
|
||||
particle:SetLifeTime(0)
|
||||
particle:SetDieTime(0)
|
||||
|
||||
particle:SetStartSize(0)
|
||||
particle:SetEndSize(0)
|
||||
|
||||
particle:SetStartAlpha(0)
|
||||
particle:SetEndAlpha(0)
|
||||
end
|
||||
|
||||
local function SlideCallback(particle, hitpos, normal)
|
||||
particle:SetBounce(1)
|
||||
local vel = particle:GetVelocity()
|
||||
vel.z = 0
|
||||
particle:SetVelocity(vel)
|
||||
particle:SetPos(hitpos + normal)
|
||||
end
|
||||
|
||||
local function StickCallback(particle, hitpos, normal)
|
||||
particle:SetAngleVelocity(Angle(0, 0, 0))
|
||||
|
||||
if particle.Align then
|
||||
local ang = normal:Angle()
|
||||
ang:RotateAroundAxis(normal, particle:GetAngles().y)
|
||||
particle:SetAngles(ang)
|
||||
end
|
||||
|
||||
if particle.Stick then
|
||||
particle:SetVelocity(Vector(0, 0, 0))
|
||||
particle:SetGravity(Vector(0, 0, 0))
|
||||
end
|
||||
|
||||
particle:SetLifeTime(0)
|
||||
particle:SetDieTime(particle.StickLifeTime or 0)
|
||||
|
||||
particle:SetStartSize(particle.StickStartSize or 0)
|
||||
particle:SetEndSize(particle.StickEndSize or 0)
|
||||
|
||||
particle:SetStartAlpha(particle.StickStartAlpha or 0)
|
||||
particle:SetEndAlpha(particle.StickEndAlpha or 0)
|
||||
end
|
||||
|
||||
function PART:GetEmitter()
|
||||
if not self.emitter then
|
||||
self.NextShot = 0
|
||||
self.Created = pac.RealTime + 0.1
|
||||
self.emitter = ParticleEmitter(vector_origin, self:Get3D())
|
||||
end
|
||||
|
||||
return self.emitter
|
||||
end
|
||||
|
||||
function PART:SetDrawManual(b)
|
||||
self.DrawManual = b
|
||||
self:GetEmitter():SetNoDraw(b)
|
||||
end
|
||||
|
||||
function PART:SetNumberParticles(num)
|
||||
self.NumberParticles = math.Clamp(num, 0, 100)
|
||||
end
|
||||
|
||||
function PART:Set3D(b)
|
||||
self["3D"] = b
|
||||
self.emitter = nil
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
self.CanKeepFiring = true
|
||||
self.FirstShot = true
|
||||
if not from_rendering then
|
||||
self.NextShot = 0
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:EmitParticles(self.Follow and vector_origin or pos, self.Follow and angle_origin or ang, ang)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not self.FireOnce then self.CanKeepFiring = true end
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
local emitter = self:GetEmitter()
|
||||
|
||||
emitter:SetPos(pos)
|
||||
if self.DrawManual or self.IgnoreZ or self.Follow or self.BlendMode ~= "" then
|
||||
|
||||
if not self.nodraw then
|
||||
emitter:SetNoDraw(true)
|
||||
self.nodraw = true
|
||||
end
|
||||
|
||||
if self.Follow then
|
||||
cam.Start3D(WorldToLocal(EyePos(), EyeAngles(), pos, ang))
|
||||
if self.IgnoreZ then cam.IgnoreZ(true) end
|
||||
emitter:Draw()
|
||||
if self.IgnoreZ then cam.IgnoreZ(false) end
|
||||
cam.End3D()
|
||||
else
|
||||
emitter:Draw()
|
||||
end
|
||||
else
|
||||
if self.nodraw then
|
||||
self:SetDrawManual(self:GetDrawManual())
|
||||
self.nodraw = false
|
||||
end
|
||||
end
|
||||
self:EmitParticles(self.Follow and vector_origin or pos, self.Follow and angle_origin or ang, ang)
|
||||
end
|
||||
|
||||
function PART:SetAdditive(b)
|
||||
self.Additive = b
|
||||
|
||||
self:SetMaterial(self:GetMaterial())
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var, function(mat)
|
||||
mat:SetFloat("$alpha", 0.999)
|
||||
mat:SetInt("$spriterendermode", self.Additive and 5 or 1)
|
||||
self.Materialm = mat
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end, "Sprite") then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
end
|
||||
|
||||
function PART:EmitParticles(pos, ang, real_ang)
|
||||
if self.FireOnce and not self.FirstShot then self.CanKeepFiring = false end
|
||||
local emt = self:GetEmitter()
|
||||
if not emt then return end
|
||||
|
||||
if self.NextShot < pac.RealTime and self.CanKeepFiring then
|
||||
if self.Material == "" then return end
|
||||
if self.Velocity == 500.01 then return end
|
||||
|
||||
local originalAng = ang
|
||||
ang = ang:Forward()
|
||||
|
||||
local double = 1
|
||||
if self.DoubleSided then
|
||||
double = 2
|
||||
end
|
||||
|
||||
for _ = 1, self.NumberParticles do
|
||||
local mats = self.Material:Split(";")
|
||||
if #mats > 1 then
|
||||
self.Materialm = pac.Material(table.Random(mats), self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
local vec = Vector()
|
||||
|
||||
if self.Spread ~= 0 then
|
||||
vec = Vector(
|
||||
math.sin(math.Rand(0, 360)) * math.Rand(-self.Spread, self.Spread),
|
||||
math.cos(math.Rand(0, 360)) * math.Rand(-self.Spread, self.Spread),
|
||||
math.sin(math.random()) * math.Rand(-self.Spread, self.Spread)
|
||||
)
|
||||
end
|
||||
|
||||
local color
|
||||
|
||||
if self.RandomColor then
|
||||
color =
|
||||
{
|
||||
math.random(math.min(self.Color1.r, self.Color2.r), math.max(self.Color1.r, self.Color2.r)),
|
||||
math.random(math.min(self.Color1.g, self.Color2.g), math.max(self.Color1.g, self.Color2.g)),
|
||||
math.random(math.min(self.Color1.b, self.Color2.b), math.max(self.Color1.b, self.Color2.b))
|
||||
}
|
||||
else
|
||||
color = {self.Color1.r, self.Color1.g, self.Color1.b}
|
||||
end
|
||||
|
||||
local roll = math.Rand(-self.RollDelta, self.RollDelta)
|
||||
|
||||
if self.PositionSpread ~= 0 then
|
||||
pos = pos + Angle(math.Rand(-180, 180), math.Rand(-180, 180), math.Rand(-180, 180)):Forward() * self.PositionSpread
|
||||
end
|
||||
|
||||
do
|
||||
local vecAdd = Vector(
|
||||
math.Rand(-self.PositionSpread2.x, self.PositionSpread2.x),
|
||||
math.Rand(-self.PositionSpread2.x, self.PositionSpread2.y),
|
||||
math.Rand(-self.PositionSpread2.z, self.PositionSpread2.z)
|
||||
)
|
||||
vecAdd:Rotate(originalAng)
|
||||
pos = pos + vecAdd
|
||||
end
|
||||
|
||||
for i = 1, double do
|
||||
local particle = emt:Add(self.Materialm or self.Material, pos)
|
||||
|
||||
if double == 2 then
|
||||
local ang_
|
||||
if i == 1 then
|
||||
ang_ = (ang * -1):Angle()
|
||||
elseif i == 2 then
|
||||
ang_ = ang:Angle()
|
||||
end
|
||||
|
||||
particle:SetAngles(ang_)
|
||||
else
|
||||
particle:SetAngles(ang:Angle())
|
||||
end
|
||||
|
||||
if self.OwnerVelocityMultiplier ~= 0 then
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
if owner:IsValid() then
|
||||
vec = vec + (owner:GetVelocity() * self.OwnerVelocityMultiplier)
|
||||
end
|
||||
end
|
||||
|
||||
particle:SetVelocity((vec + ang) * self.Velocity)
|
||||
particle:SetColor(unpack(color))
|
||||
particle:SetColor(unpack(color))
|
||||
|
||||
local life = math.Clamp(self.DieTime, 0.0001, 50)
|
||||
if self.AddFrametimeLife then
|
||||
life = life + FrameTime()
|
||||
end
|
||||
particle:SetDieTime(life)
|
||||
|
||||
particle:SetStartAlpha(self.StartAlpha)
|
||||
particle:SetEndAlpha(self.EndAlpha)
|
||||
particle:SetStartSize(self.StartSize)
|
||||
particle:SetEndSize(self.EndSize)
|
||||
particle:SetStartLength(self.StartLength)
|
||||
particle:SetEndLength(self.EndLength)
|
||||
|
||||
if self.RandomRollSpeed ~= 0 then
|
||||
particle:SetRoll(self.RandomRollSpeed * 36)
|
||||
end
|
||||
|
||||
if self.RollDelta ~= 0 then
|
||||
particle:SetRollDelta(self.RollDelta + roll)
|
||||
end
|
||||
|
||||
particle:SetAirResistance(self.AirResistance)
|
||||
particle:SetBounce(self.Bounce)
|
||||
particle:SetGravity(self.Gravity)
|
||||
if self.ZeroAngle then particle:SetAngles(Angle(0,0,0))
|
||||
else particle:SetAngles(particle:GetAngles() + self.ParticleAngle) end
|
||||
particle:SetLighting(self.Lighting)
|
||||
|
||||
if not self.Follow then
|
||||
particle:SetCollide(self.Collide)
|
||||
end
|
||||
|
||||
if self.Sliding then
|
||||
particle:SetCollideCallback(SlideCallback)
|
||||
end
|
||||
|
||||
if self["3D"] then
|
||||
if not self.Sliding then
|
||||
if i == 1 then
|
||||
particle:SetCollideCallback(RemoveCallback)
|
||||
else
|
||||
particle:SetCollideCallback(StickCallback)
|
||||
end
|
||||
end
|
||||
|
||||
particle:SetAngleVelocity(Angle(self.ParticleAngleVelocity.x, self.ParticleAngleVelocity.y, self.ParticleAngleVelocity.z))
|
||||
|
||||
particle.Align = self.Align
|
||||
particle.Stick = self.Stick
|
||||
particle.StickLifeTime = self.StickLifeTime
|
||||
particle.StickStartSize = self.StickStartSize
|
||||
particle.StickEndSize = self.StickEndSize
|
||||
particle.StickStartAlpha = self.StickStartAlpha
|
||||
particle.StickEndAlpha = self.StickEndAlpha
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.NextShot = pac.RealTime + self.FireDelay
|
||||
end
|
||||
self.FirstShot = false
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
237
lua/pac3/core/client/parts/physics.lua
Normal file
237
lua/pac3/core/client/parts/physics.lua
Normal file
@@ -0,0 +1,237 @@
|
||||
--[[
|
||||
| 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.ThinkTime = 0
|
||||
PART.ClassName = "physics"
|
||||
|
||||
PART.Group = 'model'
|
||||
PART.Icon = 'icon16/shape_handles.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Box", true)
|
||||
BUILDER:GetSet("Radius", 1)
|
||||
BUILDER:GetSet("SelfCollision", false)
|
||||
BUILDER:GetSet("Gravity", true)
|
||||
BUILDER:GetSet("Collisions", true)
|
||||
BUILDER:GetSet("Mass", 100)
|
||||
|
||||
BUILDER:GetSet("Follow", false)
|
||||
|
||||
BUILDER:GetSet("SecondsToArrive", 0.1)
|
||||
|
||||
BUILDER:GetSet("MaxSpeed", 10000)
|
||||
BUILDER:GetSet("MaxAngular", 3600)
|
||||
|
||||
BUILDER:GetSet("MaxSpeedDamp", 1000)
|
||||
BUILDER:GetSet("MaxAngularDamp", 1000)
|
||||
BUILDER:GetSet("DampFactor", 1)
|
||||
|
||||
BUILDER:GetSet("ConstrainSphere", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local function IsInvalidParent(self)
|
||||
return self.Parent.ClassName ~= "model" and self.Parent.ClassName ~= "model2"
|
||||
end
|
||||
|
||||
PART.phys = NULL
|
||||
|
||||
function PART:SetBox(b)
|
||||
self.Box = b
|
||||
self:SetRadius(self.Radius)
|
||||
end
|
||||
|
||||
function PART:SetCollisions(b)
|
||||
self.Collisions = b
|
||||
|
||||
if self.phys:IsValid() then
|
||||
self.phys:EnableCollisions(b)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMass(n)
|
||||
self.Mass = n
|
||||
|
||||
if self.phys:IsValid() then
|
||||
self.phys:SetMass(math.Clamp(n, 0.001, 50000))
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetRadius(n)
|
||||
self.Radius = n
|
||||
|
||||
if IsInvalidParent(self) then return end
|
||||
|
||||
local ent = self.Parent:GetOwner()
|
||||
|
||||
if n <= 0 then n = ent:BoundingRadius()/2 end
|
||||
|
||||
ent:SetNoDraw(false)
|
||||
|
||||
if self.Box then
|
||||
ent:PhysicsInitBox(Vector(1,1,1) * -n, Vector(1,1,1) * n)
|
||||
else
|
||||
ent:PhysicsInitSphere(n)
|
||||
end
|
||||
|
||||
self.phys = ent:GetPhysicsObject()
|
||||
|
||||
if self.Gravity ~= nil then
|
||||
self.phys:EnableGravity(self.Gravity)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetGravity(b)
|
||||
self.Gravity = b
|
||||
|
||||
if self.phys:IsValid() then
|
||||
self.phys:EnableGravity(b)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSelfCollision(b)
|
||||
self.SelfCollision = b
|
||||
|
||||
if IsInvalidParent(self) then return end
|
||||
|
||||
local ent = self.Parent:GetOwner()
|
||||
|
||||
if b then
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_NONE)
|
||||
else
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
end
|
||||
end
|
||||
|
||||
local params = {}
|
||||
|
||||
function PART:OnThink()
|
||||
|
||||
if self.Parent.GetWorldPosition then
|
||||
if self.disabled then
|
||||
self:Enable()
|
||||
end
|
||||
else
|
||||
if not self.disabled then
|
||||
self:Disable()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local phys = self.phys
|
||||
|
||||
if phys:IsValid() then
|
||||
phys:Wake()
|
||||
|
||||
if self.Follow then
|
||||
params.pos = self.Parent:GetWorldPosition()
|
||||
params.angle = self.Parent:GetWorldAngles()
|
||||
|
||||
params.secondstoarrive = math.max(self.SecondsToArrive, 0.0001)
|
||||
params.maxangular = self.MaxAngular
|
||||
params.maxangulardamp = self.MaxAngularDamp
|
||||
params.maxspeed = self.MaxSpeed
|
||||
params.maxspeeddamp = self.MaxSpeedDamp
|
||||
params.dampfactor = self.DampFactor
|
||||
|
||||
params.teleportdistance = 0
|
||||
|
||||
phys:ComputeShadowControl(params)
|
||||
|
||||
|
||||
-- this is nicer i think
|
||||
if self.ConstrainSphere ~= 0 and phys:GetPos():Distance(self.Parent:GetWorldPosition()) > self.ConstrainSphere then
|
||||
phys:SetPos(self.Parent:GetWorldPosition() + (self.Parent:GetWorldPosition() - phys:GetPos()):GetNormalized() * -self.ConstrainSphere)
|
||||
end
|
||||
else
|
||||
if self.ConstrainSphere ~= 0 then
|
||||
local offset = self.Parent:GetWorldPosition() - phys:GetPos()
|
||||
|
||||
if offset:Length() > self.ConstrainSphere then
|
||||
phys:SetPos(self.Parent:GetWorldPosition() - offset:GetNormalized() * self.ConstrainSphere)
|
||||
phys:SetVelocity(Vector())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnParent(part)
|
||||
timer.Simple(0, function() self:Enable() end)
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
timer.Simple(0, function() self:Disable() end)
|
||||
end
|
||||
|
||||
|
||||
function PART:OnShow()
|
||||
timer.Simple(0, function() self:Enable() end)
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
timer.Simple(0, function() self:Disable() end)
|
||||
end
|
||||
|
||||
function PART:Enable()
|
||||
if IsInvalidParent(self) then return end
|
||||
|
||||
local part = self:GetParent()
|
||||
|
||||
part.skip_orient = true
|
||||
|
||||
local ent = part:GetOwner()
|
||||
ent:SetNoDraw(false)
|
||||
|
||||
self:SetRadius(self.Radius)
|
||||
|
||||
for key, val in pairs(self.StorableVars) do
|
||||
if pac.registered_parts.base.StorableVars[key] then goto CONTINUE end
|
||||
self["Set" .. key](self, self[key])
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.disabled = false
|
||||
end
|
||||
|
||||
function PART:Disable()
|
||||
if IsInvalidParent(self) then return end
|
||||
|
||||
local part = self:GetParent()
|
||||
|
||||
local ent = part:GetOwner()
|
||||
if ent:IsValid() then
|
||||
-- SetNoDraw does not care of validity but PhysicsInit does?
|
||||
ent:SetNoDraw(true)
|
||||
ent:PhysicsInit(SOLID_NONE)
|
||||
end
|
||||
part.skip_orient = false
|
||||
|
||||
self.disabled = true
|
||||
end
|
||||
|
||||
function PART:SetPositionDamping(num)
|
||||
self.PositionDamping = num
|
||||
|
||||
if self.phys:IsValid() then
|
||||
self.phys:SetDamping(self.PositionDamping, self.AngleDamping)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetAngleDamping(num)
|
||||
self.AngleDamping = num
|
||||
|
||||
if self.phys:IsValid() then
|
||||
self.phys:SetDamping(self.PositionDamping, self.AngleDamping)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
157
lua/pac3/core/client/parts/player_config.lua
Normal file
157
lua/pac3/core/client/parts/player_config.lua
Normal file
@@ -0,0 +1,157 @@
|
||||
--[[
|
||||
| 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 = "player_config"
|
||||
PART.Group = "entity"
|
||||
PART.Icon = 'icon16/brick.png'
|
||||
|
||||
|
||||
local blood_colors = {
|
||||
dont_bleed = _G.DONT_BLEED,
|
||||
red = _G.BLOOD_COLOR_RED,
|
||||
yellow = _G.BLOOD_COLOR_YELLOW,
|
||||
green = _G.BLOOD_COLOR_GREEN,
|
||||
mech = _G.BLOOD_COLOR_MECH,
|
||||
antlion = _G.BLOOD_COLOR_ANTLION,
|
||||
zombie = _G.BLOOD_COLOR_ZOMBIE,
|
||||
antlion_worker = _G.BLOOD_COLOR_ANTLION_WORKER,
|
||||
}
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:GetSet("MuteSounds", false)
|
||||
BUILDER:GetSet("AllowOggWhenMuted", false)
|
||||
BUILDER:GetSet("HideBullets", false)
|
||||
BUILDER:GetSet("HidePhysgunBeam", false)
|
||||
BUILDER:GetSet("UseLegacyScale", false)
|
||||
BUILDER:GetSet("GrabEarAnimation", true)
|
||||
BUILDER:GetSet("BloodColor", "red", {enums = blood_colors})
|
||||
|
||||
BUILDER:SetPropertyGroup("behavior")
|
||||
BUILDER:GetSet("MuteFootsteps", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("death")
|
||||
BUILDER:GetSet("FallApartOnDeath", false)
|
||||
BUILDER:GetSet("DeathRagdollizeParent", true)
|
||||
BUILDER:GetSet("DrawPlayerOnDeath", false)
|
||||
BUILDER:GetSet("HideRagdollOnDeath", false)
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local ent_fields = {}
|
||||
|
||||
function BUILDER:EntityField(name, field)
|
||||
field = "pac_" .. field
|
||||
|
||||
ent_fields[field] = name
|
||||
|
||||
self.PART["Set" .. name] = function(self, val)
|
||||
self[name] = val
|
||||
|
||||
local owner = self:GetActualOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner[field] = val
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:EntityField("InverseKinematics", "enable_ik")
|
||||
BUILDER:EntityField("MuteFootsteps", "mute_footsteps")
|
||||
BUILDER:EntityField("AnimationRate", "global_animation_rate")
|
||||
BUILDER:EntityField("FallApartOnDeath", "death_physics_parts")
|
||||
BUILDER:EntityField("DeathRagdollizeParent", "death_ragdollize")
|
||||
BUILDER:EntityField("HideRagdollOnDeath", "death_hide_ragdoll")
|
||||
BUILDER:EntityField("DrawPlayerOnDeath", "draw_player_on_death")
|
||||
BUILDER:EntityField("HidePhysgunBeam", "hide_physgun_beam")
|
||||
BUILDER:EntityField("MuteSounds", "mute_sounds")
|
||||
BUILDER:EntityField("AllowOggWhenMuted", "allow_ogg_sounds")
|
||||
BUILDER:EntityField("HideBullets", "hide_bullets")
|
||||
|
||||
function PART:GetActualOwner()
|
||||
local owner = self:GetOwner()
|
||||
if owner:IsValid() and owner:GetRagdollOwner():IsPlayer() then
|
||||
return owner:GetRagdollOwner()
|
||||
end
|
||||
return owner
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local ent = self:GetActualOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:IsPlayer() then
|
||||
return ent:Nick()
|
||||
else
|
||||
return language.GetPhrase(ent:GetClass())
|
||||
end
|
||||
end
|
||||
|
||||
return self.ClassName
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetActualOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "blood_color", ent, blood_colors[self.BloodColor == "" and "red" or self.BloodColor])
|
||||
end
|
||||
|
||||
if ent:IsValid() then
|
||||
for _, field in pairs(ent_fields) do
|
||||
self["Set" .. field](self, self[field])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetActualOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_mute_footsteps = self.MuteFootsteps
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetActualOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
local player_owner = self:GetPlayerOwner()
|
||||
|
||||
pac.emut.RestoreMutations(player_owner, "blood_color", ent)
|
||||
|
||||
for key in pairs(ent_fields) do
|
||||
ent[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetBloodColor(str)
|
||||
self.BloodColor = str
|
||||
|
||||
local ent = self:GetActualOwner()
|
||||
if ent:IsValid() then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "blood_color", ent, blood_colors[self.BloodColor == "" and "red" or self.BloodColor])
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetGrabEarAnimation(b)
|
||||
self.GrabEarAnimation = b
|
||||
|
||||
local ent = self:GetActualOwner()
|
||||
if ent:IsValid() then
|
||||
ent.pac_disable_ear_grab = not b
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
88
lua/pac3/core/client/parts/poseparameter.lua
Normal file
88
lua/pac3/core/client/parts/poseparameter.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
--[[
|
||||
| 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 = "poseparameter"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = {'modifiers', 'entity'}
|
||||
PART.Icon = 'icon16/disconnect.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("PoseParameter", "", {enums = function(part) return part:GetPoseParameterList() end})
|
||||
BUILDER:GetSet("Range", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
return pac.PrettifyName(self:GetPoseParameter())
|
||||
end
|
||||
|
||||
function PART:GetPoseParameterList()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
local out = {}
|
||||
|
||||
if ent:IsValid() then
|
||||
for i = 0, ent:GetNumPoseParameters()-1 do
|
||||
local name = ent:GetPoseParameterName(i)
|
||||
if name ~= "" then
|
||||
out[name] = {name = name, i = i, range = {ent:GetPoseParameterRange(i)}}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function PART:SetRange(num)
|
||||
self.Range = num
|
||||
self:UpdateParams()
|
||||
end
|
||||
|
||||
function PART:UpdateParams()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if not self.pose_params or ent:GetModel() ~= self.last_owner_mdl then
|
||||
self.pose_params = self:GetPoseParameterList()
|
||||
self.last_owner_mdl = ent:GetModel()
|
||||
end
|
||||
|
||||
local data = self.pose_params[self.PoseParameter]
|
||||
|
||||
if data then
|
||||
local num = Lerp((self.Range + 1) / 2, data.range[1] or 0, data.range[2] or 1)
|
||||
|
||||
ent.pac_pose_params = ent.pac_pose_params or {}
|
||||
ent.pac_pose_params[self.UniqueID] = ent.pac_pose_params[self.UniqueID] or {}
|
||||
|
||||
ent.pac_pose_params[self.UniqueID].key = data.name
|
||||
ent.pac_pose_params[self.UniqueID].val = num
|
||||
|
||||
ent:SetPoseParameter(data.name, num)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_pose_params = nil
|
||||
ent:ClearPoseParameters()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(ent)
|
||||
self:UpdateParams()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
172
lua/pac3/core/client/parts/projected_texture.lua
Normal file
172
lua/pac3/core/client/parts/projected_texture.lua
Normal file
@@ -0,0 +1,172 @@
|
||||
--[[
|
||||
| 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_drawable")
|
||||
|
||||
PART.ClassName = "projected_texture"
|
||||
PART.Group = "effects"
|
||||
PART.Icon = 'icon16/lightbulb.png'
|
||||
PART.ProperColorRange = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Shadows", true)
|
||||
BUILDER:GetSet("Orthographic", false)
|
||||
|
||||
BUILDER:GetSet("NearZ", 1)
|
||||
BUILDER:GetSet("FarZ", 2048)
|
||||
|
||||
BUILDER:GetSet("FOV", 90)
|
||||
BUILDER:GetSet("HorizontalFOV", 90)
|
||||
BUILDER:GetSet("VerticalFOV", 90)
|
||||
|
||||
BUILDER:GetSet("Texture", "effects/flashlight/hard", {editor_panel = "textures"})
|
||||
BUILDER:GetSet("TextureFrame", 0)
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Brightness", 8)
|
||||
BUILDER:GetSet("Color", Vector(1, 1, 1), {editor_panel = "color2"})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetProjectedTexture()
|
||||
if not self.ptex then
|
||||
self.ptex = ProjectedTexture()
|
||||
end
|
||||
return self.ptex
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local hue = pac.ColorToNames(self:GetColor())
|
||||
return hue .. " projected texture"
|
||||
end
|
||||
|
||||
local vars = {
|
||||
"Shadows",
|
||||
|
||||
"NearZ",
|
||||
"FarZ",
|
||||
|
||||
"FOV",
|
||||
"HorizontalFOV",
|
||||
"VerticalFOV",
|
||||
|
||||
"Orthographic",
|
||||
|
||||
"Texture",
|
||||
"TextureFrame",
|
||||
|
||||
"Brightness",
|
||||
"Color",
|
||||
}
|
||||
|
||||
function PART:OnShow()
|
||||
for _, v in ipairs(vars) do
|
||||
self["Set" .. v](self, self["Get" .. v](self))
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
local ptex = self:GetProjectedTexture()
|
||||
ptex:SetPos(pos)
|
||||
ptex:SetAngles(ang)
|
||||
ptex:Update()
|
||||
end
|
||||
|
||||
|
||||
function PART:SetColor(val)
|
||||
self.Color = val
|
||||
self:GetProjectedTexture():SetColor(Color(val.x*255, val.y*255, val.z*255, 1))
|
||||
end
|
||||
|
||||
function PART:SetBrightness(val)
|
||||
self.Brightness = val
|
||||
self:GetProjectedTexture():SetBrightness(val)
|
||||
end
|
||||
|
||||
function PART:SetOrthographic(val)
|
||||
self.Orthographic = val
|
||||
self:GetProjectedTexture():SetOrthographic(val)
|
||||
end
|
||||
|
||||
function PART:SetVerticalFOV(val)
|
||||
self.VerticalFOV = val
|
||||
self:GetProjectedTexture():SetVerticalFOV(val)
|
||||
end
|
||||
|
||||
function PART:SetHorizontalFOV(val)
|
||||
self.HorizontalFOV = val
|
||||
self:GetProjectedTexture():SetHorizontalFOV(val)
|
||||
end
|
||||
|
||||
|
||||
function PART:SetFOV(val)
|
||||
self.FOV = val
|
||||
self:GetProjectedTexture():SetFOV(val)
|
||||
end
|
||||
|
||||
function PART:SetNearZ(val)
|
||||
self.NearZ = val
|
||||
self:GetProjectedTexture():SetNearZ(val)
|
||||
end
|
||||
|
||||
function PART:SetFarZ(val)
|
||||
self.FarZ = val
|
||||
self:GetProjectedTexture():SetFarZ(val)
|
||||
end
|
||||
|
||||
function PART:SetShadows(val)
|
||||
self.Shadows = val
|
||||
self:GetProjectedTexture():SetEnableShadows(val)
|
||||
end
|
||||
|
||||
function PART:SetTextureFrame(val)
|
||||
self.TextureFrame = val
|
||||
if self.vtf_frame_limit then
|
||||
self:GetProjectedTexture():SetTextureFrame(math.abs(val)%self.vtf_frame_limit)
|
||||
else
|
||||
self:GetProjectedTexture():SetTextureFrame(math.abs(val))
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetTexture(val)
|
||||
if not val then
|
||||
return
|
||||
end
|
||||
|
||||
self.Texture = val
|
||||
|
||||
if not pac.resource.DownloadTexture(val, function(tex, frames)
|
||||
if frames then
|
||||
self.vtf_frame_limit = frames
|
||||
end
|
||||
self:GetProjectedTexture():SetTexture(tex)
|
||||
end, self:GetPlayerOwner()) then
|
||||
self:GetProjectedTexture():SetTexture(val)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local tex = self:GetProjectedTexture()
|
||||
tex:SetBrightness(0)
|
||||
tex:Update()
|
||||
-- give it one frame to update
|
||||
timer.Simple(0, function()
|
||||
if tex:IsValid() then
|
||||
tex:Remove()
|
||||
end
|
||||
end)
|
||||
self.ptex = nil
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
self:OnHide()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
354
lua/pac3/core/client/parts/projectile.lua
Normal file
354
lua/pac3/core/client/parts/projectile.lua
Normal file
@@ -0,0 +1,354 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
language.Add("pac_projectile", "Projectile")
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.ClassName = "projectile"
|
||||
PART.Group = 'advanced'
|
||||
PART.Icon = 'icon16/bomb.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Speed", 1)
|
||||
BUILDER:GetSet("AddOwnerSpeed", false)
|
||||
BUILDER:GetSet("Damping", 0)
|
||||
BUILDER:GetSet("Gravity", true)
|
||||
BUILDER:GetSet("Collisions", true)
|
||||
BUILDER:GetSet("Sphere", false)
|
||||
BUILDER:GetSet("Radius", 1)
|
||||
BUILDER:GetSet("DamageRadius", 50)
|
||||
BUILDER:GetSet("LifeTime", 5)
|
||||
BUILDER:GetSet("AimDir", false)
|
||||
BUILDER:GetSet("Sticky", false)
|
||||
BUILDER:GetSet("Bounce", 0)
|
||||
BUILDER:GetSet("BulletImpact", false)
|
||||
BUILDER:GetSet("Damage", 0)
|
||||
BUILDER:GetSet("DamageType", "generic", {enums = {
|
||||
generic = 0, --generic damage
|
||||
crush = 1, --caused by physics interaction
|
||||
bullet = 2, --bullet damage
|
||||
slash = 4, --sharp objects, such as manhacks or other npcs attacks
|
||||
burn = 8, --damage from fire
|
||||
vehicle = 16, --hit by a vehicle
|
||||
fall = 32, --fall damage
|
||||
blast = 64, --explosion damage
|
||||
club = 128, --crowbar damage
|
||||
shock = 256, --electrical damage, shows smoke at the damage position
|
||||
sonic = 512, --sonic damage,used by the gargantua and houndeye npcs
|
||||
energybeam = 1024, --laser
|
||||
nevergib = 4096, --don't create gibs
|
||||
alwaysgib = 8192, --always create gibs
|
||||
drown = 16384, --drown damage
|
||||
paralyze = 32768, --same as dmg_poison
|
||||
nervegas = 65536, --neurotoxin damage
|
||||
poison = 131072, --poison damage
|
||||
acid = 1048576, --
|
||||
airboat = 33554432, --airboat gun damage
|
||||
blast_surface = 134217728, --this won't hurt the player underwater
|
||||
buckshot = 536870912, --the pellets fired from a shotgun
|
||||
direct = 268435456, --
|
||||
dissolve = 67108864, --forces the entity to dissolve on death
|
||||
drownrecover = 524288, --damage applied to the player to restore health after drowning
|
||||
physgun = 8388608, --damage done by the gravity gun
|
||||
plasma = 16777216, --
|
||||
prevent_physics_force = 2048, --
|
||||
radiation = 262144, --radiation
|
||||
removenoragdoll = 4194304, --don't create a ragdoll on death
|
||||
slowburn = 2097152, --
|
||||
|
||||
explosion = -1, -- util.BlastDamage
|
||||
fire = -1, -- ent:Ignite(5)
|
||||
|
||||
-- env_entity_dissolver
|
||||
dissolve_energy = 0,
|
||||
dissolve_heavy_electrical = 1,
|
||||
dissolve_light_electrical = 2,
|
||||
dissolve_core_effect = 3,
|
||||
|
||||
heal = -1,
|
||||
armor = -1,
|
||||
}
|
||||
})
|
||||
BUILDER:GetSet("Spread", 0)
|
||||
BUILDER:GetSet("Delay", 0)
|
||||
BUILDER:GetSet("Maximum", 0)
|
||||
BUILDER:GetSet("Mass", 100)
|
||||
BUILDER:GetSet("Attract", 0)
|
||||
BUILDER:GetSet("AttractMode", "projectile_nearest", {enums = {
|
||||
hitpos = "hitpos",
|
||||
hitpos_radius = "hitpos_radius",
|
||||
closest_to_projectile = "closest_to_projectile",
|
||||
closest_to_hitpos = "closest_to_hitpos",
|
||||
}})
|
||||
BUILDER:GetSet("AttractRadius", 200)
|
||||
BUILDER:GetSetPart("OutfitPart")
|
||||
BUILDER:GetSet("Physical", false)
|
||||
BUILDER:GetSet("CollideWithOwner", false)
|
||||
BUILDER:GetSet("CollideWithSelf", false)
|
||||
BUILDER:GetSet("RemoveOnCollide", false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
PART.Translucent = false
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
-- TODO:
|
||||
-- this makes sure all the parents of this movable have an up-to-date draw position
|
||||
-- GetBonePosition implicitly uses ent:GetPos() as the parent origin which is really bad,
|
||||
-- it should instead be using what pac considers to be the position
|
||||
--self:GetRootPart():CallRecursive("Draw", "opaque")
|
||||
local parents = self:GetParentList()
|
||||
-- call draw from root to the current part only on direct parents to update the position hiearchy
|
||||
for i = #parents, 1, -1 do
|
||||
local part = parents[i]
|
||||
if part.Draw then
|
||||
part:Draw("opaque")
|
||||
end
|
||||
end
|
||||
self:Shoot(self:GetDrawPosition())
|
||||
end
|
||||
end
|
||||
|
||||
function PART:AttachToEntity(ent)
|
||||
if not self.OutfitPart:IsValid() then return false end
|
||||
|
||||
ent.pac_draw_distance = 0
|
||||
|
||||
local tbl = self.OutfitPart:ToTable()
|
||||
|
||||
local group = pac.CreatePart("group", self:GetPlayerOwner())
|
||||
group:SetShowInEditor(false)
|
||||
|
||||
local part = pac.CreatePart(tbl.self.ClassName, self:GetPlayerOwner(), tbl, tostring(tbl))
|
||||
group:AddChild(part)
|
||||
|
||||
group:SetOwner(ent)
|
||||
group.SetOwner = function(s) s.Owner = ent end
|
||||
part:SetHide(false)
|
||||
|
||||
local id = group.Id
|
||||
local owner_id = self:GetPlayerOwnerId()
|
||||
if owner_id then
|
||||
id = id .. owner_id
|
||||
end
|
||||
|
||||
ent:CallOnRemove("pac_projectile_" .. id, function() group:Remove() end)
|
||||
group:CallRecursive("Think")
|
||||
|
||||
ent.RenderOverride = ent.RenderOverride or function()
|
||||
if self.AimDir then
|
||||
ent:SetRenderAngles(ent:GetVelocity():Angle())
|
||||
end
|
||||
end
|
||||
|
||||
ent.pac_projectile_part = group
|
||||
ent.pac_projectile = self
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local enable = CreateClientConVar("pac_sv_projectiles", 0, true)
|
||||
|
||||
function PART:Shoot(pos, ang)
|
||||
local physics = self.Physical
|
||||
|
||||
if physics then
|
||||
if pac.LocalPlayer ~= self:GetPlayerOwner() then return end
|
||||
|
||||
local tbl = {}
|
||||
for key in pairs(self:GetStorableVars()) do
|
||||
tbl[key] = self[key]
|
||||
end
|
||||
|
||||
net.Start("pac_projectile")
|
||||
net.WriteVector(pos)
|
||||
net.WriteAngle(ang)
|
||||
net.WriteTable(tbl)
|
||||
net.SendToServer()
|
||||
else
|
||||
self.projectiles = self.projectiles or {}
|
||||
|
||||
local count = 0
|
||||
|
||||
for key, ent in pairs(self.projectiles) do
|
||||
if not ent:IsValid() then
|
||||
self.projectiles[key] = nil
|
||||
else
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
local max = math.min(self.Maximum, 100)
|
||||
|
||||
if max == 0 then
|
||||
max = 100
|
||||
end
|
||||
|
||||
if count > max then
|
||||
return
|
||||
end
|
||||
|
||||
local function spawn()
|
||||
|
||||
if not self:IsValid() then return end
|
||||
|
||||
local ent = pac.CreateEntity("models/props_junk/popcan01a.mdl")
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
local idx = table.insert(self.projectiles, ent)
|
||||
|
||||
ent:AddCallback("PhysicsCollide", function(ent, data)
|
||||
local phys = ent:GetPhysicsObject()
|
||||
if self.Bounce > 0 then
|
||||
timer.Simple(0, function()
|
||||
if phys:IsValid() then
|
||||
phys:SetVelocity(data.OurOldVelocity - 2 * (data.HitNormal:Dot(data.OurOldVelocity) * data.HitNormal) * self.Bounce)
|
||||
end
|
||||
end)
|
||||
elseif self.Sticky then
|
||||
phys:SetVelocity(Vector(0,0,0))
|
||||
phys:EnableMotion(false)
|
||||
ent.pac_stuck = data.OurOldVelocity
|
||||
end
|
||||
|
||||
if self.BulletImpact then
|
||||
ent:FireBullets{
|
||||
Attacker = ent:GetOwner(),
|
||||
Damage = 0,
|
||||
Force = 0,
|
||||
Num = 1,
|
||||
Src = data.HitPos - data.HitNormal,
|
||||
Dir = data.HitNormal,
|
||||
Distance = 10,
|
||||
}
|
||||
end
|
||||
|
||||
if self.RemoveOnCollide then
|
||||
timer.Simple(0.01, function() SafeRemoveEntity(ent) end)
|
||||
end
|
||||
end)
|
||||
|
||||
ent:SetOwner(self:GetPlayerOwner(true))
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
|
||||
if self.Sphere then
|
||||
ent:PhysicsInitSphere(math.Clamp(self.Radius, 1, 30))
|
||||
else
|
||||
ent:PhysicsInitBox(Vector(1,1,1) * - math.Clamp(self.Radius, 1, 30), Vector(1,1,1) * math.Clamp(self.Radius, 1, 30))
|
||||
end
|
||||
|
||||
ent.RenderOverride = function()
|
||||
if not self:IsValid() then
|
||||
return
|
||||
end
|
||||
|
||||
if not self:GetRootPart():GetOwner():IsValid() then
|
||||
timer.Simple(0, function() SafeRemoveEntity(ent) end)
|
||||
end
|
||||
|
||||
if self.AimDir then
|
||||
if ent.pac_stuck then
|
||||
ent:SetRenderAngles(ent.pac_stuck:Angle())
|
||||
else
|
||||
local angle = ent:GetVelocity():Angle()
|
||||
ent:SetRenderAngles(angle)
|
||||
ent.last_angle = angle
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
phys:EnableGravity(self.Gravity)
|
||||
phys:AddVelocity((ang:Forward() + (VectorRand():Angle():Forward() * self.Spread)) * self.Speed * 1000)
|
||||
if self.AddOwnerSpeed and ent:GetOwner():IsValid() then
|
||||
phys:AddVelocity(ent:GetOwner():GetVelocity())
|
||||
end
|
||||
phys:EnableCollisions(self.Collisions)
|
||||
phys:SetDamping(self.Damping, 0)
|
||||
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
|
||||
if self:AttachToEntity(ent) then
|
||||
timer.Simple(math.Clamp(self.LifeTime, 0, 10), function()
|
||||
if ent:IsValid() then
|
||||
if ent.pac_projectile_part and ent.pac_projectile_part:IsValid() then
|
||||
ent.pac_projectile_part:Remove()
|
||||
end
|
||||
|
||||
timer.Simple(0.5, function()
|
||||
SafeRemoveEntity(ent)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Delay == 0 then
|
||||
spawn()
|
||||
else
|
||||
timer.Simple(self.Delay, spawn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if not self.Physical and self.projectiles then
|
||||
for key, ent in pairs(self.projectiles) do
|
||||
SafeRemoveEntity(ent)
|
||||
end
|
||||
|
||||
self.projectiles = {}
|
||||
end
|
||||
end
|
||||
--[[
|
||||
function PART:OnHide()
|
||||
if self.RemoveOnHide then
|
||||
self:OnRemove()
|
||||
end
|
||||
end
|
||||
]]
|
||||
do -- physical
|
||||
local Entity = Entity
|
||||
local projectiles = {}
|
||||
pac.AddHook("Think", "pac_projectile", function()
|
||||
for key, data in pairs(projectiles) do
|
||||
if not data.ply:IsValid() then
|
||||
projectiles[key] = nil
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
local ent = Entity(data.ent_id)
|
||||
|
||||
if ent:IsValid() and ent:GetClass() == "pac_projectile" then
|
||||
local part = pac.GetPartFromUniqueID(pac.Hash(data.ply), data.partuid)
|
||||
if part:IsValid() and part:GetPlayerOwner() == data.ply then
|
||||
part:AttachToEntity(ent)
|
||||
end
|
||||
projectiles[key] = nil
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("pac_projectile_attach", function()
|
||||
local ply = net.ReadEntity()
|
||||
local ent_id = net.ReadInt(16)
|
||||
local partuid = net.ReadString()
|
||||
|
||||
if ply:IsValid() then
|
||||
table.insert(projectiles, {ply = ply, ent_id = ent_id, partuid = partuid})
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
1234
lua/pac3/core/client/parts/proxy.lua
Normal file
1234
lua/pac3/core/client/parts/proxy.lua
Normal file
File diff suppressed because it is too large
Load Diff
420
lua/pac3/core/client/parts/script.lua
Normal file
420
lua/pac3/core/client/parts/script.lua
Normal file
@@ -0,0 +1,420 @@
|
||||
--[[
|
||||
| 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 = "script"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = 'advanced'
|
||||
PART.Icon = 'icon16/page_white_gear.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Code", "")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local blacklist = {
|
||||
"do",
|
||||
"end",
|
||||
"function",
|
||||
"repeat",
|
||||
"while",
|
||||
}
|
||||
|
||||
local lib =
|
||||
{
|
||||
math = {
|
||||
pi = math.pi,
|
||||
random = math.random,
|
||||
abs = math.abs,
|
||||
acos = math.acos,
|
||||
asin = math.asin,
|
||||
atan = math.atan,
|
||||
atan2 = math.atan2,
|
||||
ceil = math.ceil,
|
||||
cos = math.cos,
|
||||
cosh = math.cosh,
|
||||
deg = math.deg,
|
||||
exp = math.exp,
|
||||
floor = math.floor,
|
||||
frexp = math.frexp,
|
||||
ldexp = math.ldexp,
|
||||
log = math.log,
|
||||
log10 = math.log10,
|
||||
max = math.max,
|
||||
min = math.min,
|
||||
rad = math.rad,
|
||||
sin = math.sin,
|
||||
sinh = math.sinh,
|
||||
sqrt = math.sqrt,
|
||||
tanh = math.tanh,
|
||||
tan = math.tan,
|
||||
|
||||
clamp = math.Clamp,
|
||||
randomx = math.Rand,
|
||||
},
|
||||
|
||||
string = {
|
||||
find = string.find,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
local function translate_xyz(x, y, z, T, def)
|
||||
if T == "Vector" then
|
||||
|
||||
def.x = x or def.x
|
||||
def.y = y or def.y
|
||||
def.z = z or def.z
|
||||
|
||||
return def
|
||||
elseif T == "Angle" then
|
||||
|
||||
def.p = x or def.p
|
||||
def.y = y or def.y
|
||||
def.r = z or def.r
|
||||
|
||||
return def
|
||||
elseif T == "number" then
|
||||
return tonumber(x) or def -- inf protection here
|
||||
elseif T == "string" then
|
||||
return tostring(x)
|
||||
end
|
||||
end
|
||||
|
||||
local function translate_value(val, T)
|
||||
if T == "Vector" then
|
||||
return val.x, val.y, val.z
|
||||
elseif T == "Angle" then
|
||||
return val.p, val.y, val.r
|
||||
elseif T == "number" or T == "string" then
|
||||
return val
|
||||
end
|
||||
end
|
||||
|
||||
local function CreateDummies(parts)
|
||||
|
||||
local obj = {
|
||||
SetProperty = function(_, key, x, y, z)
|
||||
if not key then return end
|
||||
|
||||
for _, v in pairs(parts) do
|
||||
if v:IsValid() and v.StorableVars[key] then
|
||||
local def = v[key]
|
||||
local val = translate_xyz(x ,y, z, type(def), def)
|
||||
|
||||
v["Set" .. key](v, val)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
EventHide = function(_, b)
|
||||
for _, v in pairs(parts) do
|
||||
if v:IsValid() then
|
||||
v:SetEventTrigger(self, not not b)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
EventShow = function(_, b)
|
||||
for _, v in pairs(parts) do
|
||||
if v:IsValid() then
|
||||
v:SetEventTrigger(self, not b)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
local function CreateDummy(part, store, self)
|
||||
if not part or not part:IsValid() then return end
|
||||
if part.dummy_part then return part.dummy_part end
|
||||
|
||||
store.parts[part.UniqueID] = {}
|
||||
|
||||
local META =
|
||||
{
|
||||
SetProperty = function(_, key, x, y, z)
|
||||
if key and part.StorableVars[key] then
|
||||
local def = part[key]
|
||||
local val = translate_xyz(x ,y, z, type(def), def)
|
||||
|
||||
part["Set" .. key](part, val)
|
||||
end
|
||||
end,
|
||||
|
||||
GetProperty = function(_, key)
|
||||
if key and part.StorableVars[key] then
|
||||
local val = part["Get" .. key](part)
|
||||
|
||||
if val then
|
||||
local x, y, z = translate_value(val, type(val))
|
||||
|
||||
if x then
|
||||
return x, y, z
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
EventHide = function(_, b)
|
||||
part:SetEventTrigger(self, not not b)
|
||||
end,
|
||||
|
||||
EventShow = function(_, b)
|
||||
part:SetEventTrigger(self, not b)
|
||||
end,
|
||||
|
||||
GetChildren = function()
|
||||
return CreateDummies(part:GetChildren(), self)
|
||||
end,
|
||||
|
||||
}
|
||||
|
||||
local obj = setmetatable(
|
||||
{},
|
||||
{
|
||||
__index = function(_, key)
|
||||
if not part:IsValid() then return end
|
||||
|
||||
if store.parts[part.UniqueID][key] then
|
||||
return store.parts[part.UniqueID][key]
|
||||
end
|
||||
|
||||
return META[key]
|
||||
end,
|
||||
|
||||
__newindex = function(_, key, val)
|
||||
if not part:IsValid() then return end
|
||||
|
||||
store.parts[part.UniqueID][key] = val
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
part.dummy_part = obj
|
||||
|
||||
return obj
|
||||
end
|
||||
|
||||
local function get_entity(part)
|
||||
local ent = part:GetRootPart():GetOwner()
|
||||
return ent == pac.LocalPlayer:GetViewModel() and pac.LocalPlayer or ent
|
||||
end
|
||||
|
||||
function PART:CompileCode()
|
||||
local code = self.Code
|
||||
|
||||
for _, word in pairs(blacklist) do
|
||||
if code:find("[%p%s]" .. word) or code:find(word .. "[%p%s]") then
|
||||
return false, string.format("illegal characters used %q", word)
|
||||
end
|
||||
end
|
||||
|
||||
local func = CompileString(code, "SCRIPT_ENV", false)
|
||||
|
||||
if isstring(func) then
|
||||
return false, func
|
||||
end
|
||||
|
||||
local store = {globals = {}, parts = {}}
|
||||
|
||||
local extra_lib =
|
||||
{
|
||||
print = function(...)
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
print(...)
|
||||
|
||||
local str = ""
|
||||
local count = select("#", ...)
|
||||
|
||||
for i = 1, count do
|
||||
str = str .. tostring(select(i, ...))
|
||||
if i ~= count then
|
||||
str = str .. ", "
|
||||
end
|
||||
end
|
||||
|
||||
self.script_printing = str
|
||||
end
|
||||
end,
|
||||
|
||||
owner = {
|
||||
GetFOV = function()
|
||||
local ent = get_entity(self)
|
||||
|
||||
if ent:IsValid() then
|
||||
return ent:GetFOV()
|
||||
end
|
||||
end,
|
||||
|
||||
GetHealth = function()
|
||||
local ent = get_entity(self)
|
||||
|
||||
if ent:IsValid() then
|
||||
return ent:Health()
|
||||
end
|
||||
end,
|
||||
},
|
||||
|
||||
parts = {
|
||||
GetParent = function(level)
|
||||
level = level or 1
|
||||
local parent = self
|
||||
|
||||
for _ = 1, math.Clamp(level, 1, 30) do
|
||||
parent = parent:GetParent()
|
||||
end
|
||||
|
||||
return CreateDummy(parent, store, self)
|
||||
end,
|
||||
|
||||
FindMultiple = function(str)
|
||||
local parts = {}
|
||||
|
||||
for _, part in pairs(pac.GetParts()) do
|
||||
if
|
||||
part:GetPlayerOwner() == self:GetPlayerOwner() and
|
||||
pac.StringFind(part:GetName(), str)
|
||||
then
|
||||
table.insert(parts, part)
|
||||
end
|
||||
end
|
||||
|
||||
return CreateDummies(parts, self)
|
||||
end,
|
||||
|
||||
FindMultipleWithProperty = function()
|
||||
local parts = {}
|
||||
|
||||
for key, part in pairs(pac.GetParts()) do
|
||||
if
|
||||
part:GetPlayerOwner() == self:GetPlayerOwner() and
|
||||
part.StorableVars[key] and
|
||||
part["Get" .. key] and part["Get" .. key]()
|
||||
then
|
||||
table.insert(parts, part)
|
||||
end
|
||||
end
|
||||
|
||||
return CreateDummies(parts, self)
|
||||
end,
|
||||
|
||||
Find = function(str)
|
||||
for _, part in pairs(pac.GetParts()) do
|
||||
if
|
||||
part:GetPlayerOwner() == self:GetPlayerOwner() and
|
||||
(part.UniqueID == str or part:GetName() == str)
|
||||
then
|
||||
return CreateDummy(part, store, self)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
local env = {}
|
||||
|
||||
env.__index = function(_, key)
|
||||
if key == "this" or key == "self" then
|
||||
return CreateDummy(self, store, self)
|
||||
end
|
||||
|
||||
if key == "T" or key == "TIME" then
|
||||
return RealTime()
|
||||
end
|
||||
|
||||
if key == "CT" or key == "CURTIME" then
|
||||
return CurTime()
|
||||
end
|
||||
|
||||
if lib[key] then
|
||||
return lib[key]
|
||||
end
|
||||
|
||||
if extra_lib[key] then
|
||||
return extra_lib[key]
|
||||
end
|
||||
|
||||
if store[key] then
|
||||
return store[key]
|
||||
end
|
||||
end
|
||||
|
||||
env.__newindex = function(_, key, val)
|
||||
store[key] = val
|
||||
end
|
||||
|
||||
self.valid_functions = {
|
||||
SetProperty = "m",
|
||||
GetProperty = "m",
|
||||
GetChildren = "m",
|
||||
EventHide = "m",
|
||||
EventShow = "m",
|
||||
self = "e",
|
||||
this = "e",
|
||||
T = "e",
|
||||
TIME = "e",
|
||||
CT = "e",
|
||||
CURTIME = "e"
|
||||
}
|
||||
|
||||
local function scan(tbl)
|
||||
for key, val in pairs(tbl) do
|
||||
self.valid_functions[key] = val
|
||||
|
||||
if istable(val) then
|
||||
scan(val)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
scan(lib)
|
||||
scan(extra_lib)
|
||||
|
||||
setfenv(func, setmetatable({}, env))
|
||||
|
||||
return true, func
|
||||
end
|
||||
|
||||
function PART:ShouldHighlight(str)
|
||||
return self.valid_functions and self.valid_functions[str]
|
||||
end
|
||||
|
||||
function PART:SetCode(code)
|
||||
self.Code = code
|
||||
local ok, func = self:CompileCode()
|
||||
|
||||
if ok then
|
||||
self.func = func
|
||||
self:SetError()
|
||||
else
|
||||
self:SetError(func)
|
||||
self.func = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if self.func then
|
||||
local ok, err = pcall(self.func)
|
||||
if not ok then
|
||||
self:SetError(err)
|
||||
self.func = nil
|
||||
else
|
||||
self:SetError()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
concommand.Add("pac_register_script_part", function()
|
||||
BUILDER:Register()
|
||||
end)
|
||||
43
lua/pac3/core/client/parts/shake.lua
Normal file
43
lua/pac3/core/client/parts/shake.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| 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_movable")
|
||||
|
||||
PART.ClassName = "shake"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/transmit.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:SetPropertyGroup("shake")
|
||||
BUILDER:GetSet("Amplitude", 1)
|
||||
BUILDER:GetSet("Falloff", false)
|
||||
BUILDER:GetSet("Frequency", 1)
|
||||
BUILDER:GetSet("Duration", 0.5)
|
||||
BUILDER:GetSet("Radius", 100)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
local position = self:GetDrawPosition()
|
||||
local eyedistance = position:Distance(pac.EyePos)
|
||||
local radius = math.Clamp(self.Radius, 0.0001, 500)
|
||||
|
||||
if eyedistance < radius then
|
||||
local amplitude = self.Amplitude
|
||||
if self.Falloff then
|
||||
amplitude = amplitude * (1 - (eyedistance / radius))
|
||||
end
|
||||
util.ScreenShake(position, amplitude, self.Frequency, math.Clamp(self.Duration, 0.0001, 2), 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
346
lua/pac3/core/client/parts/sound.lua
Normal file
346
lua/pac3/core/client/parts/sound.lua
Normal file
@@ -0,0 +1,346 @@
|
||||
--[[
|
||||
| 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 webaudio = include("pac3/libraries/webaudio.lua")
|
||||
pac.webaudio2 = webaudio
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "web sound"
|
||||
PART.ClassName = "sound2"
|
||||
|
||||
PART.Icon = 'icon16/music.png'
|
||||
PART.Group = 'effects'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:GetSet("Path", "", {editor_panel = "sound"})
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("Radius", 1500)
|
||||
BUILDER:GetSet("Doppler", false)
|
||||
BUILDER:GetSet("MinPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MaxPitch", 0, {editor_sensitivity = 0.125})
|
||||
|
||||
BUILDER:SetPropertyGroup("playback")
|
||||
BUILDER:GetSet("PlayCount", 1,
|
||||
{editor_onchange =
|
||||
function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(math.max(num, 0))
|
||||
end, editor_friendly = "PlayCount (0=loop)"}
|
||||
)
|
||||
BUILDER:GetSet("Sequential",false,{description = "if there are multiple sounds (separated by ; ), plays these sounds in sequential order instead of randomly"})
|
||||
BUILDER:GetSet("SequentialStep", 1,
|
||||
{editor_onchange =
|
||||
function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(num)
|
||||
end})
|
||||
BUILDER:GetSet("StopOnHide", false)
|
||||
BUILDER:GetSet("PauseOnHide", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("filter")
|
||||
BUILDER:GetSet("FilterType", 0, {enums = {
|
||||
none = "0",
|
||||
lowpass = "1",
|
||||
highpass = "2",
|
||||
}})
|
||||
BUILDER:GetSet("FilterFraction", 1, {editor_sensitivity = 0.125, editor_clamp = {0, 1}})
|
||||
|
||||
BUILDER:SetPropertyGroup("echo")
|
||||
BUILDER:GetSet("Echo", false)
|
||||
BUILDER:GetSet("EchoDelay", 0.5, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("EchoFeedback", 0.75, {editor_sensitivity = 0.125})
|
||||
|
||||
BUILDER:SetPropertyGroup("lfo")
|
||||
BUILDER:GetSet("PitchLFOAmount", 0, {editor_sensitivity = 0.125, editor_friendly = "pitch amount"})
|
||||
BUILDER:GetSet("PitchLFOTime", 0, {editor_sensitivity = 0.125, editor_friendly = "pitch time"})
|
||||
|
||||
BUILDER:GetSet("VolumeLFOAmount", 0, {editor_sensitivity = 0.125, editor_friendly = "volume amount"})
|
||||
BUILDER:GetSet("VolumeLFOTime", 0, {editor_sensitivity = 0.125, editor_friendly = "volume time"})
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:Initialize()
|
||||
webaudio.Initialize()
|
||||
self.streams = {}
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local path = self:GetPath() .. ";"
|
||||
local tbl = {}
|
||||
for i, path in ipairs(path:Split(";")) do
|
||||
if path ~= "" then
|
||||
if path:StartWith("http") then
|
||||
path = path:gsub("%%(..)", function(char)
|
||||
local num = tonumber("0x" .. char)
|
||||
if num then
|
||||
return string.char(num)
|
||||
end
|
||||
end)
|
||||
end
|
||||
tbl[i] = pac.PrettifyName(("/".. path):match(".+/(.-)%.") or path:match("(.-)%.")) or "sound"
|
||||
end
|
||||
end
|
||||
return table.concat(tbl, ";")
|
||||
end
|
||||
|
||||
local stream_vars = {}
|
||||
|
||||
local BIND = function(propertyName, setterMethodName, check)
|
||||
table.insert(stream_vars, propertyName)
|
||||
setterMethodName = setterMethodName or "Set" .. propertyName
|
||||
PART["Set" .. propertyName] = function(self, value)
|
||||
if check then
|
||||
value = check(value)
|
||||
end
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream[setterMethodName](stream, value)
|
||||
else
|
||||
self.streams[url] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self[propertyName] = value
|
||||
end
|
||||
end
|
||||
|
||||
BIND("Pitch", "SetPlaybackRate")
|
||||
BIND("PlayCount", "SetMaxLoopCount" )
|
||||
BIND("Volume", nil, function(n) return math.Clamp(n, 0, 4) end)
|
||||
BIND("Radius", "SetSourceRadius" )
|
||||
|
||||
BIND("FilterType")
|
||||
BIND("FilterFraction")
|
||||
|
||||
BIND("Echo")
|
||||
BIND("EchoDelay")
|
||||
BIND("EchoFeedback", nil, function(n) return math.Clamp(n, 0, 0.99) end)
|
||||
|
||||
BIND("PitchLFOAmount")
|
||||
BIND("PitchLFOTime")
|
||||
|
||||
BIND("VolumeLFOAmount")
|
||||
BIND("VolumeLFOTime")
|
||||
|
||||
BIND("Doppler")
|
||||
|
||||
function PART:OnThink()
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[url] = nil goto CONTINUE end
|
||||
|
||||
if self.PlayCount == 0 then
|
||||
stream:Resume()
|
||||
end
|
||||
|
||||
if stream.owner_set ~= owner and owner:IsValid() then
|
||||
stream:SetSourceEntity(owner, true)
|
||||
stream.owner_set = owner
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
if table.Count(ent.pac_footstep_override) == 0 then
|
||||
ent.pac_footstep_override = nil
|
||||
end
|
||||
|
||||
self.last_playonfootstep = self.PlayOnFootstep
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetPath(path)
|
||||
self.seq_index = 1
|
||||
self.Path = path
|
||||
|
||||
local paths = {}
|
||||
|
||||
for _, path in ipairs(path:Split(";")) do
|
||||
local min, max = path:match(".+%[(.-),(.-)%]")
|
||||
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if min and max then
|
||||
for i = min, max do
|
||||
table.insert(paths, (path:gsub("%[.-%]", i)))
|
||||
end
|
||||
else
|
||||
table.insert(paths, path)
|
||||
end
|
||||
end
|
||||
|
||||
for _, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.streams = {}
|
||||
|
||||
local function load(path)
|
||||
local stream = webaudio.CreateStream(path)
|
||||
self.streams[path] = stream
|
||||
|
||||
stream:Set3D(true)
|
||||
stream.OnLoad = function()
|
||||
for _, key in ipairs(stream_vars) do
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
stream.OnError = function(_, err, info)
|
||||
info = info or "unknown error"
|
||||
if self:IsValid() and pac.LocalPlayer == self:GetPlayerOwner() and pace and pace.IsActive() then
|
||||
if pace and pace.current_part == self and not IsValid(pace.BusyWithProperties) then
|
||||
pace.MessagePrompt(err .. "\n" .. info, "OGG error for" .. path, "OK")
|
||||
else
|
||||
pac.Message("OGG error: ", err, " reason: ", err .. "\n" .. info, "OGG error for" .. path)
|
||||
self:SetError("OGG error: " .. err .. "\n" .. info .. "\nfor:" .. path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
stream.UpdateSourcePosition = function()
|
||||
if self:IsValid() then
|
||||
stream.SourcePosition = self:GetDrawPosition()
|
||||
end
|
||||
end
|
||||
|
||||
if
|
||||
pace and
|
||||
pace.Editor:IsValid() and
|
||||
pace.current_part:IsValid() and
|
||||
pace.current_part.ClassName == "ogg2" and
|
||||
self:GetPlayerOwner() == pac.LocalPlayer
|
||||
then
|
||||
stream:Play()
|
||||
end
|
||||
end
|
||||
|
||||
for _, path in ipairs(paths) do
|
||||
local info = sound.GetProperties(path)
|
||||
if info then
|
||||
path = info.sound
|
||||
end
|
||||
|
||||
if not string.StartsWith(path, "http") or not pac.resource.Download(path, function(path) load("data/" .. path) end)
|
||||
|
||||
then load("sound/" .. path)
|
||||
end
|
||||
end
|
||||
self.paths = paths
|
||||
end
|
||||
|
||||
PART.last_stream = NULL
|
||||
|
||||
function PART:PlaySound(_, additiveVolumeFraction)
|
||||
--PrintTable(self.streams)
|
||||
additiveVolumeFraction = additiveVolumeFraction or 0
|
||||
|
||||
local stream = table.Random(self.streams) or NULL
|
||||
if not stream:IsValid() then return end
|
||||
|
||||
if self.Sequential then
|
||||
|
||||
self.seq_index = self.seq_index or 1
|
||||
|
||||
local basepath = self.paths[self.seq_index] or self.paths[1]
|
||||
local snd = "sound/".. basepath
|
||||
|
||||
local cached_path = "data/pac3_cache/downloads/" .. pac.Hash(basepath) .. ".dat"
|
||||
|
||||
if string.find(basepath, "^http") then
|
||||
snd = cached_path
|
||||
end
|
||||
|
||||
if self.streams[snd]:IsValid() then
|
||||
stream = self.streams[snd]
|
||||
print(snd,self.seq_index)
|
||||
end
|
||||
self.seq_index = self.seq_index + self.SequentialStep
|
||||
if self.seq_index > #self.paths then
|
||||
self.seq_index = self.seq_index - #self.paths
|
||||
elseif self.seq_index < 1 then
|
||||
self.seq_index = self.seq_index + #self.paths
|
||||
end
|
||||
end
|
||||
|
||||
stream:SetAdditiveVolumeModifier(additiveVolumeFraction)
|
||||
|
||||
if self.last_stream:IsValid() and not self.Overlapping and not self.PauseOnHide then
|
||||
self.last_stream:Stop()
|
||||
end
|
||||
|
||||
if self.MinPitch ~= self.MaxPitch then
|
||||
stream:SetAdditivePitchModifier(math.Rand(self.MinPitch, self.MaxPitch))
|
||||
else
|
||||
stream:SetAdditivePitchModifier(0)
|
||||
end
|
||||
|
||||
if self.PauseOnHide then
|
||||
stream:Resume()
|
||||
else
|
||||
stream:Play()
|
||||
end
|
||||
|
||||
self.last_stream = stream
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
if self.PauseOnHide then
|
||||
stream:Pause()
|
||||
elseif self.StopOnHide then
|
||||
stream:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self:PlaySound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self:StopSound()
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
stream:Remove()
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
145
lua/pac3/core/client/parts/sprite.lua
Normal file
145
lua/pac3/core/client/parts/sprite.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
--[[
|
||||
| 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 render_SetMaterial = render.SetMaterial
|
||||
local render_DrawSprite = render.DrawSprite
|
||||
local Color = Color
|
||||
local Vector = Vector
|
||||
local cam_IgnoreZ = cam.IgnoreZ
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "sprite"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/layers.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:GetSet("IgnoreZ", false)
|
||||
BUILDER:GetSet("SizeX", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("SizeY", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("SpritePath", "sprites/grip", {editor_panel = "material"})
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
if not self:GetSpritePath() then
|
||||
return "error"
|
||||
end
|
||||
|
||||
local match = pac.PrettifyName("/" .. self:GetSpritePath()):match(".+/(.+)")
|
||||
return match and match:gsub("%..+", "") or "error"
|
||||
end
|
||||
|
||||
function PART:SetColor(v)
|
||||
self.ColorC = self.ColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.ColorC.r = v.r
|
||||
self.ColorC.g = v.g
|
||||
self.ColorC.b = v.b
|
||||
|
||||
self.Color = v
|
||||
end
|
||||
|
||||
function PART:SetAlpha(n)
|
||||
self.ColorC = self.ColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.ColorC.a = n * 255
|
||||
|
||||
self.Alpha = n
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetSpritePath(self.SpritePath)
|
||||
end
|
||||
|
||||
function PART:SetSpritePath(var)
|
||||
self:SetMaterial(var)
|
||||
end
|
||||
|
||||
function PART:FixMaterial()
|
||||
local mat = self.Materialm
|
||||
|
||||
if not mat then return end
|
||||
|
||||
local shader = mat:GetShader()
|
||||
|
||||
if shader == "VertexLitGeneric" or shader == "Cable" then
|
||||
local tex_path = mat:GetTexture("$basetexture")
|
||||
|
||||
if tex_path then
|
||||
local params = {}
|
||||
|
||||
params["$basetexture"] = tex_path:GetName()
|
||||
params["$vertexcolor"] = 1
|
||||
params["$vertexalpha"] = 1
|
||||
|
||||
self.Materialm = CreateMaterial("pac_fixmat_" .. os.clock(), "UnlitGeneric", params)
|
||||
self.Materialm:SetTexture("$basetexture", tex_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var, nil, "UnlitGeneric", {["$translucent"] = "1"}) then
|
||||
if isstring(var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
elseif type(var) == "IMaterial" then
|
||||
self.Materialm = var
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self:FixMaterial()
|
||||
|
||||
self.SpritePath = var
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local mat = self.MaterialOverride or self.Materialm
|
||||
if mat then
|
||||
if self.IgnoreZ then
|
||||
cam_IgnoreZ(true)
|
||||
end
|
||||
|
||||
local old_alpha
|
||||
if pac.drawing_motionblur_alpha then
|
||||
if not self.ColorC then self:SetColor(self:GetColor()) end
|
||||
old_alpha = self.ColorC.a
|
||||
self.ColorC.a = pac.drawing_motionblur_alpha*255
|
||||
--print(self.ColorC, pac.drawing_motionblur_alpha*255)
|
||||
end
|
||||
|
||||
local pos = self:GetDrawPosition()
|
||||
|
||||
render_SetMaterial(mat)
|
||||
render_DrawSprite(pos, self.SizeX * self.Size, self.SizeY * self.Size, self.ColorC)
|
||||
|
||||
if self.IgnoreZ then
|
||||
cam_IgnoreZ(false)
|
||||
end
|
||||
|
||||
if pac.drawing_motionblur_alpha then
|
||||
self.ColorC.a = old_alpha
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
181
lua/pac3/core/client/parts/submaterial.lua
Normal file
181
lua/pac3/core/client/parts/submaterial.lua
Normal file
@@ -0,0 +1,181 @@
|
||||
--[[
|
||||
| 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 = "submaterial"
|
||||
|
||||
PART.Icon = 'icon16/picture_edit.png'
|
||||
PART.Group = {'model', 'entity'}
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Material", "")
|
||||
BUILDER:GetSet("SubMaterialId", 1, {
|
||||
editor_onchange = function(self, num)
|
||||
num = tonumber(num) or 0
|
||||
local maxnum = 16
|
||||
|
||||
return math.floor(math.Clamp(num, 0, maxnum))
|
||||
end,
|
||||
|
||||
enums = function(part)
|
||||
local tbl = {}
|
||||
for i,v in ipairs(part:GetSubMaterialIdList()) do
|
||||
tbl[v] = tostring(i)
|
||||
end
|
||||
return tbl
|
||||
end,
|
||||
})
|
||||
BUILDER:GetSet("RootOwner", false, { hide_in_editor = true })
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:SetRootOwner(b)
|
||||
self:SetRootOwnerDeprecated(b)
|
||||
end
|
||||
|
||||
function PART:GetSubMaterialIdList()
|
||||
local out = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent.GetMaterials and #ent:GetMaterials() > 0 then
|
||||
out = ent:GetMaterials()
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function PART:UpdateSubMaterialId(id, material)
|
||||
id = tonumber(id) or self.SubMaterialId
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent ~= self.sub_last_owner then
|
||||
if IsValid(self.sub_last_owner) then
|
||||
self.sub_last_owner:SetSubMaterial(self.sub_last_owner_sub_id - 1, "")
|
||||
|
||||
if self.sub_last_owner.pac_submaterials then
|
||||
self.sub_last_owner.pac_submaterials[self.sub_last_owner_sub_id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.sub_last_owner = ent
|
||||
self.sub_last_owner_sub_id = id
|
||||
end
|
||||
|
||||
if not ent:IsValid() or not ent.GetMaterials then return end
|
||||
ent.pac_submaterials = ent.pac_submaterials or {}
|
||||
|
||||
local mat = self.Materialm
|
||||
|
||||
if not material then
|
||||
if self.Material and self.Material ~= "" and mat and not mat:IsError() then
|
||||
local matName = mat:GetName()
|
||||
material = matName:find("/", 1, true) and matName or "!" .. matName
|
||||
else
|
||||
material = ''
|
||||
end
|
||||
end
|
||||
|
||||
if id > 0 then
|
||||
ent.pac_submaterials[id] = material
|
||||
ent:SetSubMaterial(id - 1, material)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PostApplyFixes()
|
||||
self:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
function PART:SetSubMaterialId(num)
|
||||
self:UpdateSubMaterialId(self.SubMaterialId, "")
|
||||
self.SubMaterialId = tonumber(num) or 1
|
||||
self:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
function PART:FixMaterial()
|
||||
local mat = self.Materialm
|
||||
if not mat then return end
|
||||
|
||||
local shader = mat:GetShader()
|
||||
if shader ~= "UnlitGeneric" then return end
|
||||
local tex_path = mat:GetString("$basetexture")
|
||||
|
||||
if not tex_path then return end
|
||||
local params = {}
|
||||
|
||||
params["$basetexture"] = tex_path
|
||||
params["$vertexcolor"] = 1
|
||||
params["$additive"] = 1
|
||||
|
||||
self.Materialm = pac.CreateMaterial('pac_submat_fix_' .. pac.Hash(mat:GetName()), "VertexLitGeneric", params)
|
||||
end
|
||||
|
||||
function PART:UrlTextHandler()
|
||||
return function(...)
|
||||
return self:Handleurltex(...)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:Handleurltex(mat, tex)
|
||||
if not IsValid(self) then return end
|
||||
if not mat or mat:IsError() or tex:IsError() then self.Materialm = nil return end
|
||||
|
||||
self.Materialm = mat
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
|
||||
self:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var, self:UrlTextHandler()) then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:FixMaterial()
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
self:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
self:UpdateSubMaterialId()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide(force)
|
||||
if self.DefaultOnHide or force then
|
||||
self:UpdateSubMaterialId(nil, "")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
self:OnHide(true)
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
if not part:IsValid() then return end
|
||||
self:OnHide(true)
|
||||
end
|
||||
|
||||
function PART:Clear()
|
||||
self:RemoveChildren()
|
||||
self:UpdateSubMaterialId(nil, "")
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
52
lua/pac3/core/client/parts/sunbeams.lua
Normal file
52
lua/pac3/core/client/parts/sunbeams.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
--[[
|
||||
| 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 ScrW = ScrW
|
||||
local ScrH = ScrH
|
||||
local DrawSunbeams
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.ClassName = "sunbeams"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/weather_sun.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Darken", 0)
|
||||
BUILDER:GetSet("Multiplier", 0.25, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Size", 0.1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local mult = self:GetMultiplier()
|
||||
return mult > 0 and "bright sunbeams" or mult < 0 and "dark sunbeams" or self.ClassName
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not DrawSunbeams then DrawSunbeams = _G.DrawSunbeams end
|
||||
|
||||
cam.Start2D()
|
||||
local pos = self:GetDrawPosition()
|
||||
local spos = pos:ToScreen()
|
||||
|
||||
local dist_mult = - math.Clamp(pac.EyePos:Distance(pos) / 1000, 0, 1) + 1
|
||||
|
||||
DrawSunbeams(
|
||||
self.Darken,
|
||||
dist_mult * self.Multiplier * (math.Clamp(pac.EyeAng:Forward():Dot((pos - pac.EyePos):GetNormalized()) - 0.5, 0, 1) * 2) ^ 5,
|
||||
self.Size,
|
||||
spos.x / ScrW(),
|
||||
spos.y / ScrH()
|
||||
)
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
547
lua/pac3/core/client/parts/text.lua
Normal file
547
lua/pac3/core/client/parts/text.lua
Normal file
@@ -0,0 +1,547 @@
|
||||
--[[
|
||||
| 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 cam_Start3D = cam.Start3D
|
||||
local cam_Start3D2D = cam.Start3D2D
|
||||
local EyePos = EyePos
|
||||
local EyeAngles = EyeAngles
|
||||
local draw_SimpleTextOutlined = draw.SimpleTextOutlined
|
||||
local DisableClipping = DisableClipping
|
||||
local render_CullMode = render.CullMode
|
||||
local cam_End3D2D = cam.End3D2D
|
||||
local cam_End3D = cam.End3D
|
||||
--local Text_Align = TEXT_ALIGN_CENTER
|
||||
local surface_SetFont = surface.SetFont
|
||||
local Color = Color
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
local default_fonts = {
|
||||
"BudgetLabel",
|
||||
"CenterPrintText",
|
||||
"ChatFont",
|
||||
"ClientTitleFont",
|
||||
"CloseCaption_Bold",
|
||||
"CloseCaption_BoldItalic",
|
||||
"CloseCaption_Italic",
|
||||
"CloseCaption_Normal",
|
||||
"CreditsLogo",
|
||||
"CreditsOutroLogos",
|
||||
"CreditsOutroText",
|
||||
"CreditsText",
|
||||
"Crosshairs",
|
||||
"DebugFixed",
|
||||
"DebugFixedSmall",
|
||||
"DebugOverlay",
|
||||
"Default",
|
||||
"DefaultFixed",
|
||||
"DefaultFixedDropShadow",
|
||||
"DefaultSmall",
|
||||
"DefaultUnderline",
|
||||
"DefaultVerySmall",
|
||||
"HDRDemoText",
|
||||
"HL2MPTypeDeath",
|
||||
"HudDefault",
|
||||
"HudHintTextLarge",
|
||||
"HudHintTextSmall",
|
||||
"HudNumbers",
|
||||
"HudNumbersGlow",
|
||||
"HudNumbersSmall",
|
||||
"HudSelectionNumbers",
|
||||
"HudSelectionText",
|
||||
"Marlett",
|
||||
"QuickInfo",
|
||||
"TargetID",
|
||||
"TargetIDSmall",
|
||||
"Trebuchet18",
|
||||
"Trebuchet24",
|
||||
"WeaponIcons",
|
||||
"WeaponIconsSelected",
|
||||
"WeaponIconsSmall",
|
||||
"DermaDefault",
|
||||
"DermaDefaultBold",
|
||||
"DermaLarge",
|
||||
"GModNotify",
|
||||
"ScoreboardDefault",
|
||||
"ScoreboardDefaultTitle",
|
||||
"GModToolName",
|
||||
"GModToolSubtitle",
|
||||
"GModToolHelp",
|
||||
"GModToolScreen",
|
||||
"ContentHeader",
|
||||
"GModWorldtip",
|
||||
"ContentHeader",
|
||||
"DefaultBold",
|
||||
"TabLarge",
|
||||
"Trebuchet22",
|
||||
"TraitorState",
|
||||
"TimeLeft",
|
||||
"HealthAmmo",
|
||||
"cool_small",
|
||||
"cool_large",
|
||||
"treb_small"
|
||||
}
|
||||
|
||||
|
||||
PART.ClassName = "text"
|
||||
PART.Group = "effects"
|
||||
PART.Icon = "icon16/text_align_center.png"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:SetPropertyGroup("generic")
|
||||
:PropertyOrder("Name")
|
||||
:PropertyOrder("Hide")
|
||||
:GetSet("Text", "")
|
||||
:GetSet("Font", "default", {enums = default_fonts})
|
||||
:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
:GetSet("DrawMode", "DrawTextOutlined", {enums = {
|
||||
["draw.SimpleTextOutlined 3D2D"] = "DrawTextOutlined",
|
||||
["draw.SimpleTextOutlined 2D"] = "DrawTextOutlined2D",
|
||||
["surface.DrawText"] = "SurfaceText"
|
||||
}})
|
||||
|
||||
:SetPropertyGroup("text layout")
|
||||
:GetSet("HorizontalTextAlign", TEXT_ALIGN_CENTER, {enums = {["Left"] = "0", ["Center"] = "1", ["Right"] = "2"}})
|
||||
:GetSet("VerticalTextAlign", TEXT_ALIGN_CENTER, {enums = {["Center"] = "1", ["Top"] = "3", ["Bottom"] = "4"}})
|
||||
:GetSet("ConcatenateTextAndOverrideValue",false,{editor_friendly = "CombinedText"})
|
||||
:GetSet("TextPosition","Prefix", {enums = {["Prefix"] = "Prefix", ["Postfix"] = "Postfix"}},{editor_friendly = "ConcatenateMode"})
|
||||
|
||||
:SetPropertyGroup("data source")
|
||||
:GetSet("TextOverride", "Text", {enums = {
|
||||
["Proxy value (DynamicTextValue)"] = "Proxy",
|
||||
["Text"] = "Text",
|
||||
["Health"] = "Health",
|
||||
["Maximum Health"] = "MaxHealth",
|
||||
["Armor"] = "Armor",
|
||||
["Maximum Armor"] = "MaxArmor",
|
||||
["Timerx"] = "Timerx",
|
||||
["CurTime"] = "CurTime",
|
||||
["RealTime"] = "RealTime",
|
||||
["Velocity"] = "Velocity",
|
||||
["Velocity Vector"] = "VelocityVector",
|
||||
["Position Vector"] = "PositionVector",
|
||||
["Owner Position Vector"] = "OwnerPositionVector",
|
||||
["Clip current Ammo"] = "Ammo",
|
||||
["Clip Size"] = "ClipSize",
|
||||
["Ammo Reserve"] = "AmmoReserve",
|
||||
["Sequence Name"] = "SequenceName",
|
||||
["Weapon Name"] = "Weapon",
|
||||
["Vehicle Class"] = "VehicleClass",
|
||||
["Model Name"] = "ModelName",
|
||||
["Model Path"] = "ModelPath",
|
||||
["Player Name"] = "PlayerName",
|
||||
["Player SteamID"] = "SteamID",
|
||||
["Map"] = "Map",
|
||||
["Ground Surface"] = "GroundSurface",
|
||||
["Ground Entity Class"] = "GroundEntityClass",
|
||||
["Players"] = "Players",
|
||||
["Max Players"] = "MaxPlayers",
|
||||
["Difficulty"] = "GameDifficulty"
|
||||
}})
|
||||
:GetSet("DynamicTextValue", 0)
|
||||
:GetSet("RoundingPosition", 2, {editor_onchange = function(self, num)
|
||||
return math.Round(num,0)
|
||||
end})
|
||||
|
||||
:SetPropertyGroup("orientation")
|
||||
:PropertyOrder("AimPartName")
|
||||
:PropertyOrder("Bone")
|
||||
:PropertyOrder("Position")
|
||||
:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("ForceAdditive",false, {description = "additive rendering for the surface.DrawText mode"})
|
||||
BUILDER:GetSet("Outline", 0)
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("OutlineColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("OutlineAlpha", 1, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Clamp(num, 0, 1)
|
||||
end})
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
:SetPropertyGroup("CustomFont")
|
||||
:GetSet("CreateCustomFont",false, {description = "Tries to create a custom font.\nHeavily throttled as creating fonts is an expensive process.\nSupport is limited because of the fonts' supported features and the limits of Lua strings.\nFont names include those stored in your operating system. for example: Comic Sans MS, Ink Free"})
|
||||
:GetSet("CustomFont", "DermaDefault")
|
||||
:GetSet("FontSize", 13)
|
||||
:GetSet("FontWeight",500)
|
||||
:GetSet("FontBlurSize",0)
|
||||
:GetSet("FontScanLines",0)
|
||||
:GetSet("FontAntialias",true)
|
||||
:GetSet("FontUnderline",false)
|
||||
:GetSet("FontItalic",false)
|
||||
:GetSet("FontStrikeout",false)
|
||||
:GetSet("FontSymbol",false)
|
||||
:GetSet("FontRotary",false)
|
||||
:GetSet("Shadow",false)
|
||||
:GetSet("FontAdditive",false)
|
||||
:GetSet("FontOutline",false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
if self.TextOverride ~= "Text" then return self.TextOverride end
|
||||
|
||||
return 'Text: "' .. self:GetText() .. '"'
|
||||
end
|
||||
|
||||
function PART:SetColor(v)
|
||||
self.ColorC = self.ColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.ColorC.r = v.r
|
||||
self.ColorC.g = v.g
|
||||
self.ColorC.b = v.b
|
||||
|
||||
self.Color = v
|
||||
end
|
||||
|
||||
function PART:SetAlpha(n)
|
||||
self.ColorC = self.ColorC or Color(255, 255, 255, 255)
|
||||
self.ColorC.a = n * 255
|
||||
|
||||
self.Alpha = n
|
||||
end
|
||||
|
||||
function PART:SetOutlineColor(v)
|
||||
self.OutlineColorC = self.OutlineColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.OutlineColorC.r = v.r
|
||||
self.OutlineColorC.g = v.g
|
||||
self.OutlineColorC.b = v.b
|
||||
|
||||
self.OutlineColor = v
|
||||
end
|
||||
|
||||
function PART:SetOutlineAlpha(n)
|
||||
self.OutlineColorC = self.OutlineColorC or Color(255, 255, 255, 255)
|
||||
self.OutlineColorC.a = n * 255
|
||||
|
||||
self.OutlineAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetFont(str)
|
||||
self.UsedFont = str
|
||||
if not self.CreateCustomFont then
|
||||
if not pcall(surface_SetFont, str) then
|
||||
if #self.Font > 20 then
|
||||
|
||||
self.lastwarn = self.lastwarn or CurTime()
|
||||
if self.lastwarn > CurTime() + 1 then
|
||||
pac.Message(Color(255,150,0),str.." Font not found! Could be custom font, trying again in 4 seconds!")
|
||||
self.lastwarn = CurTime()
|
||||
end
|
||||
timer.Simple(4, function()
|
||||
if not pcall(surface_SetFont, str) then
|
||||
pac.Message(Color(255,150,0),str.." Font still not found! Reverting to DermaDefault!")
|
||||
str = "DermaDefault"
|
||||
self.UsedFont = str
|
||||
end
|
||||
end)
|
||||
else
|
||||
timer.Simple(5, function()
|
||||
if not pcall(surface_SetFont, str) then
|
||||
pac.Message(Color(255,150,0),str.." Font still not found! Reverting to DermaDefault!")
|
||||
str = "DermaDefault"
|
||||
self.UsedFont = str
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.Font = self.UsedFont
|
||||
end
|
||||
local lastfontcreationtime = 0
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:CheckFont()
|
||||
if not pcall(surface_SetFont, self.UsedFont) then return end
|
||||
|
||||
local DisplayText = self.Text or ""
|
||||
if self.TextOverride == "Text" then goto DRAW end
|
||||
DisplayText = ""
|
||||
if self.TextOverride == "Health" then DisplayText = self:GetRootPart():GetOwner():Health()
|
||||
elseif self.TextOverride == "MaxHealth" then
|
||||
DisplayText = self:GetRootPart():GetOwner():GetMaxHealth()
|
||||
elseif self.TextOverride == "Ammo" then
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetActiveWeapon():Clip1() or ""
|
||||
elseif self.TextOverride == "ClipSize" then
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetActiveWeapon():GetMaxClip1() or ""
|
||||
elseif self.TextOverride == "AmmoReserve" then
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetAmmoCount(self:GetPlayerOwner():GetActiveWeapon():GetPrimaryAmmoType()) or ""
|
||||
elseif self.TextOverride == "Armor" then
|
||||
DisplayText = self:GetPlayerOwner():Armor()
|
||||
elseif self.TextOverride == "MaxArmor" then
|
||||
DisplayText = self:GetPlayerOwner():GetMaxArmor()
|
||||
elseif self.TextOverride == "Timerx" then
|
||||
DisplayText = ""..math.Round(CurTime() - self.time,self.RoundingPosition)
|
||||
elseif self.TextOverride == "CurTime" then
|
||||
DisplayText = ""..math.Round(CurTime(),self.RoundingPosition)
|
||||
elseif self.TextOverride == "RealTime" then
|
||||
DisplayText = ""..math.Round(RealTime(),self.RoundingPosition)
|
||||
elseif self.TextOverride == "Velocity" then
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
DisplayText = math.Round(ent:GetVelocity():Length(),2)
|
||||
elseif self.TextOverride == "VelocityVector" then
|
||||
local ent = self:GetOwner() or self:GetRootPart():GetOwner()
|
||||
local vec = ent:GetVelocity()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "PositionVector" then
|
||||
local vec = self:GetDrawPosition()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "OwnerPositionVector" then
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
local vec = ent:GetPos()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "SequenceName" then
|
||||
DisplayText = self:GetRootPart():GetOwner():GetSequenceName(self:GetPlayerOwner():GetSequence())
|
||||
elseif self.TextOverride == "PlayerName" then
|
||||
DisplayText = self:GetPlayerOwner():GetName()
|
||||
elseif self.TextOverride == "SteamID" then
|
||||
DisplayText = self:GetPlayerOwner():SteamID()
|
||||
elseif self.TextOverride == "ModelName" then
|
||||
local path = self:GetRootPart():GetOwner():GetModel() or "null"
|
||||
path = string.Split(path, "/")[#string.Split(path, "/")]
|
||||
path = string.gsub(path,".mdl","")
|
||||
DisplayText = path
|
||||
elseif self.TextOverride == "ModelPath" then
|
||||
DisplayText = self:GetPlayerOwner():GetModel()
|
||||
elseif self.TextOverride == "Map" then
|
||||
DisplayText = game.GetMap()
|
||||
elseif self.TextOverride == "GroundSurface" then
|
||||
local trace = util.TraceLine( {
|
||||
start = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, 30),
|
||||
endpos = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, -60 ),
|
||||
filter = function(ent)
|
||||
if ent == self:GetRootPart():GetOwner() or ent == self:GetPlayerOwner() then return false else return true end
|
||||
end
|
||||
})
|
||||
if trace.Hit then
|
||||
if trace.MatType == MAT_ANTLION then DisplayText = "Antlion"
|
||||
elseif trace.MatType == MAT_BLOODYFLESH then DisplayText = "Bloody Flesh"
|
||||
elseif trace.MatType == MAT_CONCRETE then DisplayText = "Concrete"
|
||||
elseif trace.MatType == MAT_DIRT then DisplayText = "Dirt"
|
||||
elseif trace.MatType == MAT_EGGSHELL then DisplayText = "Egg Shell"
|
||||
elseif trace.MatType == MAT_FLESH then DisplayText = "Flesh"
|
||||
elseif trace.MatType == MAT_GRATE then DisplayText = "Grate"
|
||||
elseif trace.MatType == MAT_ALIENFLESH then DisplayText = "Alien Flesh"
|
||||
elseif trace.MatType == MAT_CLIP then DisplayText = "Clip"
|
||||
elseif trace.MatType == MAT_SNOW then DisplayText = "Snow"
|
||||
elseif trace.MatType == MAT_PLASTIC then DisplayText = "Plastic"
|
||||
elseif trace.MatType == MAT_METAL then DisplayText = "Metal"
|
||||
elseif trace.MatType == MAT_SAND then DisplayText = "Sand"
|
||||
elseif trace.MatType == MAT_FOLIAGE then DisplayText = "Foliage"
|
||||
elseif trace.MatType == MAT_COMPUTER then DisplayText = "Computer"
|
||||
elseif trace.MatType == MAT_SLOSH then DisplayText = "Slime"
|
||||
elseif trace.MatType == MAT_TILE then DisplayText = "Tile"
|
||||
elseif trace.MatType == MAT_GRASS then DisplayText = "Grass"
|
||||
elseif trace.MatType == MAT_VENT then DisplayText = "Grass"
|
||||
elseif trace.MatType == MAT_WOOD then DisplayText = "Wood"
|
||||
elseif trace.MatType == MAT_DEFAULT then DisplayText = "Default"
|
||||
elseif trace.MatType == MAT_GLASS then DisplayText = "Glass"
|
||||
elseif trace.MatType == MAT_WARPSHIELD then DisplayText = "Warp Shield"
|
||||
else DisplayText = "Other Surface" end
|
||||
else DisplayText = "Air" end
|
||||
elseif self.TextOverride == "GroundEntityClass" then
|
||||
local trace = util.TraceLine( {
|
||||
start = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, 30),
|
||||
endpos = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, -60 ),
|
||||
filter = function(ent)
|
||||
if ent == self:GetRootPart():GetOwner() or ent == self:GetPlayerOwner() then return false else return true end
|
||||
end
|
||||
})
|
||||
if trace.Hit then
|
||||
DisplayText = trace.Entity:GetClass()
|
||||
end
|
||||
elseif self.TextOverride == "GameDifficulty" then
|
||||
local diff = game.GetSkillLevel()
|
||||
if diff == 1 then DisplayText = "Easy"
|
||||
elseif diff == 2 then DisplayText = "Normal"
|
||||
elseif diff == 3 then DisplayText = "Hard" end
|
||||
elseif self.TextOverride == "Players" then
|
||||
DisplayText = #player.GetAll()
|
||||
elseif self.TextOverride == "MaxPlayers" then
|
||||
DisplayText = game.MaxPlayers()
|
||||
elseif self.TextOverride == "Weapon" then
|
||||
if IsValid(self:GetPlayerOwner():GetActiveWeapon()) then
|
||||
DisplayText = self:GetPlayerOwner():GetActiveWeapon():GetClass()
|
||||
else DisplayText = "unarmed" end
|
||||
elseif self.TextOverride == "VehicleClass" then
|
||||
if IsValid(self:GetPlayerOwner():GetVehicle()) then
|
||||
DisplayText = self:GetPlayerOwner():GetVehicle():GetClass()
|
||||
else DisplayText = "not driving" end
|
||||
elseif self.TextOverride == "Proxy" then
|
||||
DisplayText = ""..math.Round(self.DynamicTextValue,self.RoundingPosition)
|
||||
end
|
||||
|
||||
if self.ConcatenateTextAndOverrideValue then
|
||||
if self.TextPosition == "Prefix" then
|
||||
DisplayText = ""..self.Text..DisplayText
|
||||
elseif self.TextPosition == "Postfix" then
|
||||
DisplayText = ""..DisplayText..self.Text
|
||||
end
|
||||
end
|
||||
|
||||
::DRAW::
|
||||
|
||||
if DisplayText ~= "" then
|
||||
if self.DrawMode == "DrawTextOutlined" then
|
||||
cam_Start3D(EyePos(), EyeAngles())
|
||||
cam_Start3D2D(pos, ang, self.Size)
|
||||
local oldState = DisableClipping(true)
|
||||
|
||||
draw_SimpleTextOutlined(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
|
||||
draw_SimpleTextOutlined(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
|
||||
DisableClipping(oldState)
|
||||
cam_End3D2D()
|
||||
cam_End3D()
|
||||
cam_Start3D(EyePos(), EyeAngles())
|
||||
cam_Start3D2D(pos, ang, self.Size)
|
||||
local oldState = DisableClipping(true)
|
||||
|
||||
draw.SimpleText(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
|
||||
draw.SimpleText(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
|
||||
DisableClipping(oldState)
|
||||
cam_End3D2D()
|
||||
cam_End3D()
|
||||
elseif self.DrawMode == "SurfaceText" or self.DrawMode == "DrawTextOutlined2D" then
|
||||
hook.Add("HUDPaint", "pac.DrawText"..self.UniqueID, function()
|
||||
if not pcall(surface_SetFont, self.UsedFont) then return end
|
||||
self:SetFont(self.UsedFont)
|
||||
|
||||
surface.SetTextColor(self.Color.r, self.Color.g, self.Color.b, 255*self.Alpha)
|
||||
|
||||
surface.SetFont(self.UsedFont)
|
||||
local pos2d = self:GetDrawPosition():ToScreen()
|
||||
local w, h = surface.GetTextSize(DisplayText)
|
||||
|
||||
if self.HorizontalTextAlign == 0 then --left
|
||||
pos2d.x = pos2d.x
|
||||
elseif self.HorizontalTextAlign == 1 then --center
|
||||
pos2d.x = pos2d.x - w/2
|
||||
elseif self.HorizontalTextAlign == 2 then --right
|
||||
pos2d.x = pos2d.x - w
|
||||
end
|
||||
|
||||
if self.VerticalTextAlign == 1 then --center
|
||||
pos2d.y = pos2d.y - h/2
|
||||
elseif self.VerticalTextAlign == 3 then --top
|
||||
pos2d.y = pos2d.y
|
||||
elseif self.VerticalTextAlign == 4 then --bottom
|
||||
pos2d.y = pos2d.y - h
|
||||
end
|
||||
|
||||
surface.SetTextPos(pos2d.x, pos2d.y)
|
||||
local dist = (EyePos() - self:GetWorldPosition()):Length()
|
||||
local fadestartdist = 200
|
||||
local fadeenddist = 1000
|
||||
if fadestartdist == 0 then fadestartdist = 0.1 end
|
||||
if fadeenddist == 0 then fadeenddist = 0.1 end
|
||||
|
||||
if fadestartdist > fadeenddist then
|
||||
local temp = fadestartdist
|
||||
fadestartdist = fadeenddist
|
||||
fadeenddist = temp
|
||||
end
|
||||
|
||||
if dist < fadeenddist then
|
||||
if dist < fadestartdist then
|
||||
if self.DrawMode == "DrawTextOutlined2D" then
|
||||
draw.SimpleTextOutlined(DisplayText, self.UsedFont, pos2d.x, pos2d.y, Color(self.Color.r,self.Color.g,self.Color.b,255*self.Alpha), TEXT_ALIGN_TOP, TEXT_ALIGN_LEFT, self.Outline, Color(self.OutlineColor.r,self.OutlineColor.g,self.OutlineColor.b, 255*self.OutlineAlpha))
|
||||
elseif self.DrawMode == "SurfaceText" then
|
||||
surface.DrawText(DisplayText, self.ForceAdditive)
|
||||
end
|
||||
|
||||
else
|
||||
local fade = math.pow(math.Clamp(1 - (dist-fadestartdist)/fadeenddist,0,1),3)
|
||||
|
||||
if self.DrawMode == "DrawTextOutlined2D" then
|
||||
draw.SimpleTextOutlined(DisplayText, self.UsedFont, pos2d.x, pos2d.y, Color(self.Color.r,self.Color.g,self.Color.b,255*self.Alpha*fade), TEXT_ALIGN_TOP, TEXT_ALIGN_LEFT, self.Outline, Color(self.OutlineColor.r,self.OutlineColor.g,self.OutlineColor.b, 255*self.OutlineAlpha*fade))
|
||||
elseif self.DrawMode == "SurfaceText" then
|
||||
surface.SetTextColor(self.Color.r * fade, self.Color.g * fade, self.Color.b * fade)
|
||||
surface.DrawText(DisplayText, true)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
if self.DrawMode == "DrawTextOutlined" then
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
else hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID) end
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self:TryCreateFont()
|
||||
end
|
||||
|
||||
function PART:CheckFont()
|
||||
if self.CreateCustomFont then
|
||||
lastfontcreationtime = lastfontcreationtime or 0
|
||||
if lastfontcreationtime + 3 <= CurTime() then
|
||||
self:TryCreateFont()
|
||||
end
|
||||
else
|
||||
self:SetFont(self.Font)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PART:TryCreateFont()
|
||||
if "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID == self.lastcustomfont then
|
||||
self.UsedFont = "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID
|
||||
return
|
||||
end
|
||||
if self.CreateCustomFont then
|
||||
local newfont = "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID
|
||||
surface.CreateFont( newfont, {
|
||||
font = self.CustomFont, -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
|
||||
extended = self.Extended,
|
||||
size = self.FontSize,
|
||||
weight = self.Weight,
|
||||
blursize = self.BlurSize,
|
||||
scanlines = self.ScanLines,
|
||||
antialias = self.Antialias,
|
||||
underline = self.Underline,
|
||||
italic = self.Italic,
|
||||
strikeout = self.Strikeout,
|
||||
symbol = self.Symbol,
|
||||
rotary = self.Rotary,
|
||||
shadow = self.Shadow,
|
||||
additive = self.Additive,
|
||||
outline = self.Outline,
|
||||
} )
|
||||
self:SetFont(newfont)
|
||||
self.lastcustomfont = newfont
|
||||
lastfontcreationtime = CurTime()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self.time = CurTime()
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
function PART:OnRemove()
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
function PART:SetText(str)
|
||||
self.Text = str
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
195
lua/pac3/core/client/parts/trail.lua
Normal file
195
lua/pac3/core/client/parts/trail.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
| 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 Lerp = Lerp
|
||||
local tonumber = tonumber
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
local math_ceil = math.ceil
|
||||
local math_abs = math.abs
|
||||
local math_min = math.min
|
||||
local render_StartBeam = render.StartBeam
|
||||
local cam_IgnoreZ = cam.IgnoreZ
|
||||
local render_EndBeam = render.EndBeam
|
||||
local render_AddBeam = render.AddBeam
|
||||
local render_SetMaterial = render.SetMaterial
|
||||
local Vector = Vector
|
||||
local RealTime = RealTime
|
||||
|
||||
local temp_color = Color(255, 255, 255)
|
||||
|
||||
function pac.DrawTrail(self, len, spc, pos, ang, mat, scr,scg,scb,sca, ecr,ecg,ecb,eca, start_size, end_size, stretch)
|
||||
self.trail_points = self.trail_points or {}
|
||||
local points = self.trail_points
|
||||
|
||||
if pac.drawing_motionblur_alpha then
|
||||
local a = pac.drawing_motionblur_alpha
|
||||
self.trail_points_motionblur = self.trail_points_motionblur or {}
|
||||
self.trail_points_motionblur[a] = self.trail_points_motionblur[a] or {}
|
||||
points = self.trail_points_motionblur[a]
|
||||
end
|
||||
|
||||
local time = RealTime()
|
||||
|
||||
if not points[1] or points[#points].pos:Distance(pos) > spc then
|
||||
table_insert(points, {pos = pos * 1, life_time = time + len})
|
||||
end
|
||||
|
||||
local count = #points
|
||||
|
||||
render_SetMaterial(mat)
|
||||
|
||||
render_StartBeam(count)
|
||||
for i = #points, 1, -1 do
|
||||
local data = points[i]
|
||||
|
||||
local f = (data.life_time - time)/len
|
||||
local f2 = f
|
||||
f = -f+1
|
||||
|
||||
local coord = (1 / count) * (i - 1)
|
||||
|
||||
temp_color.r = math_min(Lerp(coord, ecr, scr), 255)
|
||||
temp_color.g = math_min(Lerp(coord, ecg, scg), 255)
|
||||
temp_color.b = math_min(Lerp(coord, ecb, scb), 255)
|
||||
temp_color.a = math_min(Lerp(coord, eca, sca), 255)
|
||||
|
||||
render_AddBeam(data.pos, (f * start_size) + (f2 * end_size), coord * stretch, temp_color)
|
||||
|
||||
if f >= 1 then
|
||||
table_remove(points, i)
|
||||
end
|
||||
end
|
||||
render_EndBeam()
|
||||
|
||||
if self.CenterAttraction ~= 0 then
|
||||
local attraction = FrameTime() * self.CenterAttraction
|
||||
local center = Vector(0,0,0)
|
||||
for _, data in ipairs(points) do
|
||||
center:Zero()
|
||||
for _, data in ipairs(points) do
|
||||
center:Add(data.pos)
|
||||
end
|
||||
center:Mul(1 / #points)
|
||||
center:Sub(data.pos)
|
||||
center:Mul(attraction)
|
||||
|
||||
data.pos:Add(center)
|
||||
end
|
||||
end
|
||||
|
||||
if not self.Gravity:IsZero() then
|
||||
local gravity = self.Gravity * FrameTime()
|
||||
gravity:Rotate(ang)
|
||||
for _, data in ipairs(points) do
|
||||
data.pos:Add(gravity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "trail"
|
||||
PART.ClassName = "trail2"
|
||||
PART.Icon = 'icon16/arrow_undo.png'
|
||||
PART.Group = 'effects'
|
||||
PART.ProperColorRange = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:GetSet("Duration", 1)
|
||||
:GetSet("Spacing", 0.25)
|
||||
:GetSet("StartSize", 3)
|
||||
:GetSet("EndSize", 0)
|
||||
:GetSet("StartColor", Vector(1, 1, 1), {editor_panel = "color2"})
|
||||
:GetSet("EndColor", Vector(1, 1, 1), {editor_panel = "color2"})
|
||||
:GetSet("StartAlpha", 1)
|
||||
:GetSet("EndAlpha", 0)
|
||||
:GetSet("Stretch", 1)
|
||||
:GetSet("CenterAttraction", 0)
|
||||
:GetSet("Gravity", Vector(0,0,0))
|
||||
:GetSet("IgnoreZ", false)
|
||||
:GetSet("TrailPath", "trails/laser", {editor_panel = "material"})
|
||||
:GetSet("Translucent", true)
|
||||
:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetTrailPath())
|
||||
local matched = str and str:match(".+/(.+)")
|
||||
return matched and matched:gsub("%..+", "") or "error"
|
||||
end
|
||||
|
||||
PART.LastAdd = 0
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetTrailPath(self.TrailPath)
|
||||
end
|
||||
|
||||
function PART:SetTrailPath(var)
|
||||
self.TrailPath = var
|
||||
self:SetMaterial(var)
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var, function(mat)
|
||||
self.Materialm = mat
|
||||
self:MakeMaterialUnlit()
|
||||
end) then
|
||||
if isstring(var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
elseif type(var) == "IMaterial" then
|
||||
self.Materialm = var
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
self:MakeMaterialUnlit()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:MakeMaterialUnlit()
|
||||
if not self.Materialm then return end
|
||||
|
||||
local shader = self.Materialm:GetShader()
|
||||
if shader == "VertexLitGeneric" or shader == "Cable" or shader == "LightmappedGeneric" then
|
||||
self.Materialm = pac.MakeMaterialUnlitGeneric(self.Materialm, self.Id)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
local mat = self.material_override and self.material_override[0][1] and self.material_override[0][1]:GetRawMaterial() or self.Materialm
|
||||
if not mat then return end
|
||||
pac.DrawTrail(
|
||||
self,
|
||||
math.min(self.Duration, 10),
|
||||
self.Spacing + (self.StartSize/10),
|
||||
pos,
|
||||
ang,
|
||||
mat,
|
||||
|
||||
self.StartColor.x*255, self.StartColor.y*255, self.StartColor.z*255,self.StartAlpha*255,
|
||||
self.EndColor.x*255, self.EndColor.y*255, self.EndColor.z*255,self.EndAlpha*255,
|
||||
|
||||
self.StartSize,
|
||||
self.EndSize,
|
||||
1/self.Stretch
|
||||
)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
Reference in New Issue
Block a user