This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 8064ba84d8
commit 73479cff9e
7338 changed files with 1718883 additions and 14 deletions

View 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()

View 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()

View 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()

View 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()

View 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

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()