mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
2221 lines
53 KiB
Lua
2221 lines
53 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
local FrameTime = FrameTime
|
|
local CurTime = CurTime
|
|
local NULL = NULL
|
|
local Vector = Vector
|
|
local util = util
|
|
local SysTime = SysTime
|
|
|
|
local BUILDER, PART = pac.PartTemplate("base")
|
|
|
|
PART.ClassName = "event"
|
|
|
|
PART.ThinkTime = 0
|
|
PART.AlwaysThink = true
|
|
PART.Icon = 'icon16/clock.png'
|
|
|
|
BUILDER:StartStorableVars()
|
|
BUILDER:GetSet("Event", "", {enums = function(part)
|
|
local output = {}
|
|
|
|
for i, event in pairs(part.Events) do
|
|
if not event.IsAvailable or event:IsAvailable(part) then
|
|
output[i] = event
|
|
end
|
|
end
|
|
|
|
return output
|
|
end})
|
|
BUILDER:GetSet("Operator", "find simple", {enums = function(part) local tbl = {} for i,v in ipairs(part.Operators) do tbl[v] = v end return tbl end})
|
|
BUILDER:GetSet("Arguments", "", {hidden = true})
|
|
BUILDER:GetSet("Invert", true)
|
|
BUILDER:GetSet("RootOwner", true)
|
|
BUILDER:GetSet("AffectChildrenOnly", false)
|
|
BUILDER:GetSet("ZeroEyePitch", false)
|
|
BUILDER:GetSetPart("TargetPart")
|
|
BUILDER:EndStorableVars()
|
|
|
|
function PART:SetEvent(event)
|
|
local reset = (self.Arguments == "") or
|
|
(self.Arguments ~= "" and self.Event ~= "" and self.Event ~= event)
|
|
|
|
self.Event = event
|
|
self:SetWarning()
|
|
self:GetDynamicProperties(reset)
|
|
end
|
|
|
|
local function get_default(typ)
|
|
if typ == "string" then
|
|
return ""
|
|
elseif typ == "number" then
|
|
return 0
|
|
elseif typ == "boolean" then
|
|
return false
|
|
end
|
|
end
|
|
|
|
local function string_to_type(typ, val)
|
|
if typ == "number" then
|
|
return tonumber(val) or 0
|
|
elseif typ == "boolean" then
|
|
return tobool(val) or false
|
|
end
|
|
return val
|
|
end
|
|
|
|
local function cast(typ, val)
|
|
if val == nil then
|
|
val = get_default(typ)
|
|
end
|
|
|
|
return string_to_type(typ, val)
|
|
end
|
|
|
|
function PART:GetDynamicProperties(reset_to_default)
|
|
local data = self.Events[self.Event]
|
|
if not data then return end
|
|
|
|
local tbl = {}
|
|
for pos, arg in ipairs(data:GetArguments()) do
|
|
local key, typ, udata = unpack(arg)
|
|
udata = udata or {}
|
|
udata.group = udata.group or "arguments"
|
|
|
|
tbl[key] = {
|
|
key = key,
|
|
get = function()
|
|
local args = {self:GetParsedArguments(data)}
|
|
return cast(typ, args[pos])
|
|
end,
|
|
set = function(val)
|
|
local args = {self:GetParsedArguments(data)}
|
|
args[pos] = val
|
|
self:ParseArguments(unpack(args))
|
|
end,
|
|
udata = udata,
|
|
}
|
|
|
|
local arg = tbl[key]
|
|
if arg.get() == nil or reset_to_default then
|
|
if udata.default then
|
|
arg.set(udata.default)
|
|
else
|
|
arg.set(nil)
|
|
end
|
|
end
|
|
end
|
|
|
|
return tbl
|
|
end
|
|
|
|
local function convert_angles(self, ang)
|
|
if self.ZeroEyePitch then
|
|
ang.p = 0
|
|
end
|
|
|
|
return ang
|
|
end
|
|
|
|
local function calc_velocity(part)
|
|
if not part.GetWorldPosition then
|
|
return vector_origin
|
|
end
|
|
|
|
local diff = part:GetWorldPosition() - (part.last_pos or Vector(0, 0, 0))
|
|
part.last_pos = part:GetWorldPosition()
|
|
|
|
part.last_vel_smooth = part.last_vel_smooth or Vector(0, 0, 0)
|
|
part.last_vel_smooth = part.last_vel_smooth + (part:GetWorldPosition() - part.last_vel_smooth) * FrameTime() * 4
|
|
|
|
return part.last_vel_smooth
|
|
end
|
|
|
|
local function try_viewmodel(ent)
|
|
return ent == pac.LocalViewModel and pac.LocalPlayer or ent
|
|
end
|
|
|
|
local function get_owner(self)
|
|
if self.RootOwner then
|
|
return try_viewmodel(self:GetRootPart():GetOwner())
|
|
else
|
|
return try_viewmodel(self:GetOwner())
|
|
end
|
|
end
|
|
|
|
local movetypes = {}
|
|
|
|
for k,v in pairs(_G) do
|
|
if isstring(k) and isnumber(v) and k:sub(0,9) == "MOVETYPE_" then
|
|
movetypes[v] = k:sub(10):lower()
|
|
end
|
|
end
|
|
|
|
PART.Events = {}
|
|
PART.OldEvents = {
|
|
random = {
|
|
arguments = {{compare = "number"}},
|
|
callback = function(self, ent, compare)
|
|
return self:NumberOperator(math.random(), compare)
|
|
end,
|
|
},
|
|
|
|
randint = {
|
|
arguments = {{compare = "number"}, {min = "number"}, {max = "number"}},
|
|
callback = function(self, ent, compare, min, max)
|
|
min = min or 0
|
|
max = max or 1
|
|
if min > max then return 0 end
|
|
return self:NumberOperator(math.random(min,max), compare)
|
|
end,
|
|
},
|
|
|
|
random_timer = {
|
|
arguments = {{min = "number"}, {max = "number"}, {holdtime = "number"}},
|
|
callback = function(self, ent, min, max, holdtime)
|
|
|
|
holdtime = holdtime or 0.1
|
|
min = min or 0
|
|
max = max or 1
|
|
|
|
if min > max then return false end
|
|
|
|
if self.RndTime == nil then
|
|
self.RndTime = 0
|
|
end
|
|
|
|
if not self.SetRandom then
|
|
self.RndTime = CurTime() + math.random(min,max)
|
|
self.SetRandom = true
|
|
elseif self.SetRandom then
|
|
|
|
if CurTime() > self.RndTime then
|
|
if CurTime() < self.RndTime + holdtime then
|
|
return true
|
|
end
|
|
|
|
self.SetRandom = false
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
end,
|
|
},
|
|
|
|
timerx = {
|
|
arguments = {{seconds = "number"}, {reset_on_hide = "boolean"}, {synced_time = "boolean"}},
|
|
nice = function(self, ent, seconds)
|
|
return "timerx: " .. ("%.2f"):format(self.number or 0, 2) .. " " .. self:GetOperator() .. " " .. seconds .. " seconds?"
|
|
end,
|
|
callback = function(self, ent, seconds, reset_on_hide, synced_time)
|
|
local time = synced_time and CurTime() or RealTime()
|
|
|
|
self.time = self.time or time
|
|
self.timerx_reset = reset_on_hide
|
|
|
|
if self.AffectChildrenOnly and self:IsHiddenBySomethingElse() then
|
|
return false
|
|
end
|
|
self.number = time - self.time
|
|
|
|
return self:NumberOperator(self.number, seconds)
|
|
end,
|
|
},
|
|
|
|
timersys = {
|
|
arguments = {{seconds = "number"}, {reset_on_hide = "boolean"}},
|
|
|
|
callback = function(self, ent, seconds, reset_on_hide)
|
|
local time = SysTime()
|
|
|
|
self.time = self.time or time
|
|
self.timerx_reset = reset_on_hide
|
|
|
|
if self.AffectChildrenOnly and self:IsHiddenBySomethingElse() then
|
|
return false
|
|
end
|
|
return self:NumberOperator(time - self.time, seconds)
|
|
end,
|
|
},
|
|
|
|
map_name = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
return self:StringOperator(game.GetMap(), find)
|
|
end,
|
|
},
|
|
|
|
fov = {
|
|
arguments = {{fov = "number"}},
|
|
callback = function(self, ent, fov)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent.GetFOV then
|
|
return self:NumberOperator(ent:GetFOV(), fov)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
health_lost = {
|
|
arguments = {{amount = "number"}},
|
|
callback = function(self, ent, amount)
|
|
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent.Health then
|
|
|
|
local dmg = self.pac_lastdamage or 0
|
|
|
|
if self.dmgCD == nil then
|
|
self.dmgCD = 0
|
|
end
|
|
|
|
if not self.pac_wasdmg then
|
|
|
|
local dmgDone = dmg - ent:Health()
|
|
self.pac_lastdamage = ent:Health()
|
|
|
|
if dmgDone == 0 then return false end
|
|
|
|
if self:NumberOperator(dmgDone,amount) then
|
|
self.pac_wasdmg = true
|
|
self.dmgCD = pac.RealTime + 0.2
|
|
end
|
|
|
|
else
|
|
|
|
if self.pac_wasdmg and pac.RealTime > self.dmgCD then
|
|
self.pac_wasdmg = false
|
|
end
|
|
|
|
end
|
|
|
|
return self.pac_wasdmg
|
|
end
|
|
|
|
return false
|
|
end,
|
|
},
|
|
|
|
holdtype = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
ent = try_viewmodel(ent)
|
|
local wep = ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
|
if wep:IsValid() and self:StringOperator(wep:GetHoldType(), find) then
|
|
return true
|
|
end
|
|
end,
|
|
},
|
|
|
|
is_crouching = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.Crouching and ent:Crouching()
|
|
end,
|
|
},
|
|
|
|
is_typing = {
|
|
callback = function(self, ent)
|
|
ent = self:GetPlayerOwner()
|
|
return ent.IsTyping and ent:IsTyping()
|
|
end,
|
|
},
|
|
|
|
using_physgun = {
|
|
callback = function(self, ent)
|
|
ent = self:GetPlayerOwner()
|
|
local pac_drawphysgun_event_part = ent.pac_drawphysgun_event_part
|
|
if not pac_drawphysgun_event_part then
|
|
pac_drawphysgun_event_part = {}
|
|
ent.pac_drawphysgun_event_part = pac_drawphysgun_event_part
|
|
end
|
|
pac_drawphysgun_event_part[self] = true
|
|
return ent.pac_drawphysgun_event ~= nil
|
|
end,
|
|
},
|
|
|
|
eyetrace_entity_class = {
|
|
arguments = {{class = "string"}},
|
|
callback = function(self, ent, find)
|
|
if ent.GetEyeTrace then
|
|
ent = ent:GetEyeTrace().Entity
|
|
if self:StringOperator(ent:GetClass(), find) then
|
|
return true
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
owner_health = {
|
|
arguments = {{health = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
if ent.Health then
|
|
return self:NumberOperator(ent:Health(), num)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_max_health = {
|
|
arguments = {{health = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
if ent.GetMaxHealth then
|
|
return self:NumberOperator(ent:GetMaxHealth(), num)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_alive = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
if ent.Alive then
|
|
return ent:Alive()
|
|
end
|
|
return 0
|
|
end,
|
|
},
|
|
owner_armor = {
|
|
arguments = {{armor = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
if ent.Armor then
|
|
return self:NumberOperator(ent:Armor(), num)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
|
|
owner_scale_x = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
|
|
return self:NumberOperator(ent.pac_model_scale and ent.pac_model_scale.x or (ent.GetModelScale and ent:GetModelScale()) or 1, num)
|
|
end,
|
|
},
|
|
owner_scale_y = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
|
|
return self:NumberOperator(ent.pac_model_scale and ent.pac_model_scale.y or (ent.GetModelScale and ent:GetModelScale()) or 1, num)
|
|
end,
|
|
},
|
|
owner_scale_z = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
|
|
return self:NumberOperator(ent.pac_model_scale and ent.pac_model_scale.z or (ent.GetModelScale and ent:GetModelScale()) or 1, num)
|
|
end,
|
|
},
|
|
|
|
pose_parameter = {
|
|
arguments = {{name = "string"}, {num = "number"}},
|
|
callback = function(self, ent, name, num)
|
|
ent = try_viewmodel(ent)
|
|
return self:NumberOperator(ent:GetPoseParameter(name), num)
|
|
end,
|
|
},
|
|
|
|
speed = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
return self:NumberOperator(ent:GetVelocity():Length(), num)
|
|
end,
|
|
},
|
|
|
|
is_under_water = {
|
|
arguments = {{level = "number"}},
|
|
callback = function(self, ent, num)
|
|
ent = try_viewmodel(ent)
|
|
return self:NumberOperator(ent:WaterLevel(), num)
|
|
end,
|
|
},
|
|
|
|
is_on_fire = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent:IsOnFire()
|
|
end,
|
|
},
|
|
|
|
client_spawned = {
|
|
arguments = {{time = "number"}},
|
|
callback = function(self, ent, time)
|
|
time = time or 0.1
|
|
ent = try_viewmodel(ent)
|
|
if ent.pac_playerspawn and ent.pac_playerspawn + time > pac.RealTime then
|
|
return true
|
|
end
|
|
end,
|
|
},
|
|
|
|
is_client = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return self:GetPlayerOwner() == ent
|
|
end,
|
|
},
|
|
|
|
is_flashlight_on = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.FlashlightIsOn and ent:FlashlightIsOn()
|
|
end,
|
|
},
|
|
|
|
collide = {
|
|
callback = function(self, ent)
|
|
ent.pac_event_collide_callback = ent.pac_event_collide_callback or ent:AddCallback("PhysicsCollide", function(ent, data)
|
|
ent.pac_event_collision_data = data
|
|
end)
|
|
|
|
if ent.pac_event_collision_data then
|
|
local data = ent.pac_event_collision_data
|
|
ent.pac_event_collision_data = nil
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end,
|
|
},
|
|
|
|
ranger = {
|
|
arguments = {{distance = "number"}, {compare = "number"}, {npcs_and_players_only = "boolean"}},
|
|
userdata = {{editor_panel = "ranger", ranger_property = "distance"}, {editor_panel = "ranger", ranger_property = "compare"}},
|
|
callback = function(self, ent, distance, compare, npcs_and_players_only)
|
|
local parent = self:GetParentEx()
|
|
|
|
if parent:IsValid() and parent.GetWorldPosition then
|
|
self:SetWarning()
|
|
distance = distance or 1
|
|
compare = compare or 0
|
|
|
|
local res = util.TraceLine({
|
|
start = parent:GetWorldPosition(),
|
|
endpos = parent:GetWorldPosition() + parent:GetWorldAngles():Forward() * distance,
|
|
filter = ent,
|
|
})
|
|
|
|
if npcs_and_players_only and (not res.Entity:IsPlayer() and not res.Entity:IsNPC()) then
|
|
return false
|
|
end
|
|
|
|
return self:NumberOperator(res.Fraction * distance, compare)
|
|
else
|
|
local classname = parent:GetNiceName()
|
|
local name = parent:GetName()
|
|
self:SetWarning(("ranger doesn't work on [%s] %s"):format(classname, classname ~= name and "(" .. name .. ")" or ""))
|
|
end
|
|
end,
|
|
},
|
|
|
|
is_on_ground = {
|
|
arguments = {{exclude_noclip = "boolean"}},
|
|
callback = function(self, ent, exclude_noclip)
|
|
ent = try_viewmodel(ent)
|
|
if exclude_noclip and ent:GetMoveType() == MOVETYPE_NOCLIP then return false end
|
|
--return ent.IsOnGround and ent:IsOnGround()
|
|
|
|
local rad = ent:BoundingRadius() / 2
|
|
local times = 2
|
|
|
|
for x = -times, times do
|
|
for y = -times, times do
|
|
local xy = Vector(x/times,y/times,0) * rad
|
|
local res = util.TraceLine({
|
|
start = ent:GetPos() + xy + Vector(0,0,2.5),
|
|
endpos = ent:GetPos() + xy/1.25 + Vector(0,0,-10),
|
|
--mins = ent:OBBMins(),
|
|
--maxs = ent:OBBMaxs(),
|
|
filter = ent,
|
|
--mask = MASK_SOLID_BRUSHONLY,
|
|
})
|
|
if res.Hit and math.abs(res.HitNormal.z) > 0.70 then return true end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end,
|
|
},
|
|
|
|
is_touching = {
|
|
arguments = {{extra_radius = "number"}},
|
|
userdata = {{editor_panel = "is_touching", is_touching_property = "extra_radius"}},
|
|
callback = function(self, ent, extra_radius)
|
|
extra_radius = extra_radius or 0
|
|
|
|
local radius = ent:BoundingRadius()
|
|
|
|
if radius == 0 and IsValid(ent.pac_projectile) then
|
|
radius = ent.pac_projectile:GetRadius()
|
|
end
|
|
|
|
radius = math.max(radius + extra_radius + 1, 1)
|
|
|
|
local mins = Vector(-1,-1,-1)
|
|
local maxs = Vector(1,1,1)
|
|
local startpos = ent:WorldSpaceCenter()
|
|
mins = mins * radius
|
|
maxs = maxs * radius
|
|
|
|
local tr = util.TraceHull( {
|
|
start = startpos,
|
|
endpos = startpos,
|
|
maxs = maxs,
|
|
mins = mins,
|
|
filter = ent
|
|
} )
|
|
return tr.Hit
|
|
end,
|
|
},
|
|
|
|
is_in_noclip = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent:GetMoveType() == MOVETYPE_NOCLIP and (not ent.GetVehicle or not ent:GetVehicle():IsValid())
|
|
end,
|
|
},
|
|
|
|
is_voice_chatting = {
|
|
callback = function(self, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.IsSpeaking and ent:IsSpeaking()
|
|
end,
|
|
},
|
|
|
|
ammo = {
|
|
arguments = {{primary = "boolean"}, {amount = "number"}},
|
|
userdata = {{editor_onchange = function(part, num) return math.Round(num) end}},
|
|
callback = function(self, ent, primary, amount)
|
|
ent = try_viewmodel(ent)
|
|
ent = ent.GetActiveWeapon and ent:GetActiveWeapon() or ent
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(ent.Clip1 and (primary and ent:Clip1() or ent:Clip2()) or 0, amount)
|
|
end
|
|
end,
|
|
},
|
|
total_ammo = {
|
|
arguments = {{ammo_id = "string"}, {amount = "number"}},
|
|
callback = function(self, ent, ammo_id, amount)
|
|
if ent.GetAmmoCount then
|
|
ammo_id = tonumber(ammo_id) or ammo_id:lower()
|
|
if ammo_id == "primary" then
|
|
local wep = ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
|
return self:NumberOperator(wep:IsValid() and ent:GetAmmoCount(wep:GetPrimaryAmmoType()) or 0, amount)
|
|
elseif ammo_id == "secondary" then
|
|
local wep = ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
|
return self:NumberOperator(wep:IsValid() and ent:GetAmmoCount(wep:GetSecondaryAmmoType()) or 0, amount)
|
|
else
|
|
return self:NumberOperator(ent:GetAmmoCount(ammo_id), amount)
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
clipsize = {
|
|
arguments = {{primary = "boolean"}, {amount = "number"}},
|
|
callback = function(self, ent, primary, amount)
|
|
ent = try_viewmodel(ent)
|
|
ent = ent.GetActiveWeapon and ent:GetActiveWeapon() or ent
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(ent.GetMaxClip1 and (primary and ent:GetMaxClip1() or ent:GetMaxClip2()) or 0, amount)
|
|
end
|
|
end,
|
|
},
|
|
|
|
vehicle_class = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
ent = try_viewmodel(ent)
|
|
ent = ent.GetVehicle and ent:GetVehicle() or NULL
|
|
|
|
if ent:IsValid() then
|
|
return self:StringOperator(ent:GetClass(), find)
|
|
end
|
|
end,
|
|
},
|
|
|
|
vehicle_model = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
ent = try_viewmodel(ent)
|
|
ent = ent.GetVehicle and ent:GetVehicle() or NULL
|
|
|
|
if ent:IsValid() and ent:GetModel() then
|
|
return self:StringOperator(ent:GetModel():lower(), find)
|
|
end
|
|
end,
|
|
},
|
|
|
|
driver_name = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
ent = ent.GetDriver and ent:GetDriver() or NULL
|
|
|
|
if ent:IsValid() then
|
|
return self:StringOperator(ent:GetName(), find)
|
|
end
|
|
end,
|
|
},
|
|
|
|
entity_class = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
return self:StringOperator(ent:GetClass(), find)
|
|
end,
|
|
},
|
|
|
|
weapon_class = {
|
|
arguments = {{find = "string"}, {hide = "boolean"}},
|
|
callback = function(self, ent, find, hide)
|
|
ent = try_viewmodel(ent)
|
|
|
|
local wep = ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
|
|
|
if wep:IsValid() then
|
|
local class_name = wep:GetClass()
|
|
local found = self:StringOperator(class_name, find)
|
|
|
|
if class_name == "hands" and not found then
|
|
found = self:StringOperator("none", find)
|
|
end
|
|
|
|
if found then
|
|
wep:SetNoDraw(hide)
|
|
wep.pac_weapon_class = true
|
|
return true
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
has_weapon = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
ent = try_viewmodel(ent)
|
|
local tbl = ent.GetWeapons and ent:GetWeapons()
|
|
if tbl then
|
|
for _, val in pairs(tbl) do
|
|
val = val:GetClass()
|
|
if self:StringOperator(val, find) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
model_name = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
return self:StringOperator(ent:GetModel(), find)
|
|
end,
|
|
},
|
|
|
|
sequence_name = {
|
|
arguments = {{find = "string"}},
|
|
nice = function(self, ent)
|
|
return self.sequence_name or "invalid sequence"
|
|
end,
|
|
callback = function(self, ent, find)
|
|
ent = get_owner(self)
|
|
|
|
self.sequence_name = ent:GetSequenceName(ent:GetSequence())
|
|
|
|
return self:StringOperator(self.sequence_name, find)
|
|
end,
|
|
},
|
|
|
|
timer = {
|
|
arguments = {{interval = "number"}, {offset = "number"}},
|
|
callback = function(self, ent, interval, offset)
|
|
interval = interval or 1
|
|
offset = offset or 0
|
|
|
|
if interval == 0 or interval < FrameTime() then
|
|
self.timer_hack = not self.timer_hack
|
|
return self.timer_hack
|
|
end
|
|
|
|
return (CurTime() + offset) % interval > (interval / 2)
|
|
end,
|
|
},
|
|
|
|
animation_event = {
|
|
arguments = {{find = "string"}, {time = "number"}},
|
|
nice = function(self)
|
|
return self.anim_name or ""
|
|
end,
|
|
callback = function(self, ent, find, time)
|
|
time = time or 0.1
|
|
|
|
ent = get_owner(self)
|
|
|
|
local data = ent.pac_anim_event
|
|
local b = false
|
|
|
|
if data and (self:StringOperator(data.name, find) and (time == 0 or data.time + time > pac.RealTime)) then
|
|
data.reset = false
|
|
b = true
|
|
end
|
|
|
|
if b then
|
|
self.anim_name = data.name
|
|
else
|
|
self.anim_name = nil
|
|
end
|
|
|
|
return b
|
|
end,
|
|
},
|
|
|
|
fire_bullets = {
|
|
arguments = {{find_ammo = "string"}, {time = "number"}},
|
|
callback = function(self, ent, find, time)
|
|
time = time or 0.1
|
|
|
|
ent = try_viewmodel(ent)
|
|
|
|
local data = ent.pac_fire_bullets
|
|
local b = false
|
|
|
|
if data and (self:StringOperator(data.name, find) and (time == 0 or data.time + time > pac.RealTime)) then
|
|
data.reset = false
|
|
b = true
|
|
end
|
|
|
|
return b
|
|
end,
|
|
},
|
|
|
|
emit_sound = {
|
|
arguments = {{find_sound = "string"}, {time = "number"}, {mute = "boolean"}},
|
|
callback = function(self, ent, find, time, mute)
|
|
time = time or 0.1
|
|
|
|
ent = try_viewmodel(ent)
|
|
|
|
local data = ent.pac_emit_sound
|
|
local b = false
|
|
|
|
if data and (self:StringOperator(data.name, find) and (time == 0 or data.time + time > pac.RealTime)) then
|
|
data.reset = false
|
|
b = true
|
|
if mute then
|
|
data.mute_me = true
|
|
end
|
|
end
|
|
|
|
return b
|
|
end,
|
|
},
|
|
|
|
command = {
|
|
arguments = {{find = "string"}, {time = "number"}, {hide_in_eventwheel = "boolean"}},
|
|
userdata = {
|
|
{default = "change_me", editor_friendly = "CommandName"},
|
|
{default = 0.1, editor_friendly = "EventDuration"},
|
|
{default = false, group = "event wheel", editor_friendly = "HideInEventWheel"}
|
|
},
|
|
nice = function(self, ent, find, time)
|
|
find = find or "?"
|
|
time = time or "?"
|
|
return "command: " .. find .. " | " .. "duration: " .. time
|
|
end,
|
|
callback = function(self, ent, find, time)
|
|
time = time or 0.1
|
|
|
|
local ply = self:GetPlayerOwner()
|
|
|
|
local events = ply.pac_command_events
|
|
|
|
if events then
|
|
local found = nil
|
|
for _, data in pairs(events) do
|
|
if self:StringOperator(data.name, find) then
|
|
if data.on > 0 then
|
|
found = data.on == 1
|
|
elseif data.time + time > pac.RealTime then
|
|
found = true
|
|
end
|
|
end
|
|
end
|
|
return found
|
|
end
|
|
end,
|
|
},
|
|
|
|
say = {
|
|
arguments = {{find = "string"}, {time = "number"}, {all_players = "boolean"}},
|
|
callback = function(self, ent, find, time, all_players)
|
|
time = time or 0.1
|
|
|
|
ent = try_viewmodel(ent)
|
|
|
|
if all_players then
|
|
for _, ply in ipairs(player.GetAll()) do
|
|
local data = ply.pac_say_event
|
|
|
|
if data and self:StringOperator(data.str, find) and data.time + time > pac.RealTime then
|
|
return true
|
|
end
|
|
end
|
|
else
|
|
local owner = self:GetRootPart():GetOwner()
|
|
if owner:IsValid() then
|
|
local data = owner.pac_say_event
|
|
|
|
if data and self:StringOperator(data.str, find) and data.time + time > pac.RealTime then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
},
|
|
|
|
-- outfit owner
|
|
owner_velocity_length = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
local parent = self:GetParentEx()
|
|
ent = try_viewmodel(ent)
|
|
|
|
if parent:IsValid() and ent:IsValid() then
|
|
return self:NumberOperator(get_owner(parent):GetVelocity():Length(), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_forward = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(convert_angles(self, ent:EyeAngles()):Forward():Dot(ent:GetVelocity()), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_right = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(convert_angles(self, ent:EyeAngles()):Right():Dot(ent:GetVelocity()), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_up = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(convert_angles(self, ent:EyeAngles()):Up():Dot(ent:GetVelocity()), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_world_forward = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if owner:IsValid() then
|
|
return self:NumberOperator(ent:GetVelocity()[1], speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_world_right = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(ent:GetVelocity()[2], speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
owner_velocity_world_up = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
ent = try_viewmodel(ent)
|
|
|
|
if ent:IsValid() then
|
|
return self:NumberOperator(ent:GetVelocity()[3], speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
|
|
-- parent part
|
|
parent_velocity_length = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() then
|
|
return self:NumberOperator(calc_velocity(parent):Length(), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
parent_velocity_forward = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() and parent.GetWorldAngles then
|
|
return self:NumberOperator(parent:GetWorldAngles():Forward():Dot(calc_velocity(parent)), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
parent_velocity_right = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() and parent.GetWorldAngles then
|
|
return self:NumberOperator(parent:GetWorldAngles():Right():Dot(calc_velocity(parent)), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
parent_velocity_up = {
|
|
arguments = {{speed = "number"}},
|
|
callback = function(self, ent, speed)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() and parent.GetWorldAngles then
|
|
return self:NumberOperator(parent:GetWorldAngles():Up():Dot(calc_velocity(parent)), speed)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
|
|
parent_scale_x = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() then
|
|
return self:NumberOperator((parent.Type == "part" and parent.Scale and parent.Scale.x * parent.Size) or (parent.pac_model_scale and parent.pac_model_scale.x) or (parent.GetModelScale and parent:GetModelScale()) or 1, num)
|
|
end
|
|
|
|
return 1
|
|
end,
|
|
},
|
|
parent_scale_y = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() then
|
|
return self:NumberOperator((parent.Type == "part" and parent.Scale and parent.Scale.y * parent.Size) or (parent.pac_model_scale and parent.pac_model_scale.y) or (parent.GetModelScale and parent:GetModelScale()) or 1, num)
|
|
end
|
|
|
|
return 1
|
|
end,
|
|
},
|
|
parent_scale_z = {
|
|
arguments = {{scale = "number"}},
|
|
callback = function(self, ent, num)
|
|
local parent = self:GetParentEx()
|
|
|
|
if not self.TargetPart:IsValid() and parent:HasParent() then
|
|
parent = parent:GetParent()
|
|
end
|
|
|
|
if parent:IsValid() then
|
|
return self:NumberOperator((parent.Type == "part" and parent.Scale and parent.Scale.z * parent.Size) or (parent.pac_model_scale and parent.pac_model_scale.z) or (parent.GetModelScale and parent:GetModelScale()) or 1, num)
|
|
end
|
|
|
|
return 1
|
|
end,
|
|
},
|
|
|
|
gravitygun_punt = {
|
|
arguments = {{time = "number"}},
|
|
callback = function(self, ent, time)
|
|
time = time or 0.1
|
|
|
|
ent = try_viewmodel(ent)
|
|
|
|
local punted = ent.pac_gravgun_punt
|
|
|
|
if punted and punted + time > pac.RealTime then
|
|
return true
|
|
end
|
|
end,
|
|
},
|
|
|
|
movetype = {
|
|
arguments = {{find = "string"}},
|
|
callback = function(self, ent, find)
|
|
local mt = ent:GetMoveType()
|
|
if movetypes[mt] then
|
|
return self:StringOperator(movetypes[mt], find)
|
|
end
|
|
end,
|
|
},
|
|
|
|
dot_forward = {
|
|
arguments = {{normal = "number"}},
|
|
callback = function(self, ent, normal)
|
|
|
|
local owner = self:GetRootPart():GetOwner()
|
|
|
|
if owner:IsValid() then
|
|
local ang = owner:EyeAngles()
|
|
ang.p = 0
|
|
return self:NumberOperator(pac.EyeAng:Forward():Dot(ang:Forward()), normal)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
|
|
dot_right = {
|
|
arguments = {{normal = "number"}},
|
|
callback = function(self, ent, normal)
|
|
|
|
local owner = self:GetRootPart():GetOwner()
|
|
|
|
if owner:IsValid() then
|
|
local ang = owner:EyeAngles()
|
|
ang.p = 0
|
|
return self:NumberOperator(pac.EyeAng:Right():Dot(ang:Forward()), normal)
|
|
end
|
|
|
|
return 0
|
|
end,
|
|
},
|
|
|
|
flat_dot_forward = {
|
|
arguments = {{normal = "number"}},
|
|
callback = function(self, ent, normal)
|
|
local owner = self:GetRootPart():GetOwner()
|
|
|
|
if owner:IsValid() then
|
|
local ang = owner:EyeAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
local dir = pac.EyePos - owner:EyePos()
|
|
dir[3] = 0
|
|
dir:Normalize()
|
|
return self:NumberOperator(dir:Dot(ang:Forward()), normal)
|
|
end
|
|
|
|
return 0
|
|
end
|
|
},
|
|
|
|
flat_dot_right = {
|
|
arguments = {{normal = "number"}},
|
|
callback = function(self, ent, normal)
|
|
local owner = self:GetRootPart():GetOwner()
|
|
|
|
if owner:IsValid() then
|
|
local ang = owner:EyeAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
local dir = pac.EyePos - owner:EyePos()
|
|
dir[3] = 0
|
|
dir:Normalize()
|
|
return self:NumberOperator(dir:Dot(ang:Right()), normal)
|
|
end
|
|
|
|
return 0
|
|
end
|
|
}
|
|
}
|
|
|
|
do
|
|
local enums = {}
|
|
local enums2 = {}
|
|
for key, val in pairs(_G) do
|
|
if isstring(key) and isnumber(val) then
|
|
if key:sub(0,4) == "KEY_" and not key:find("_LAST$") and not key:find("_FIRST$") and not key:find("_COUNT$") then
|
|
enums[val] = key:sub(5):lower()
|
|
enums2[enums[val]] = val
|
|
elseif (key:sub(0,6) == "MOUSE_" or key:sub(0,9) == "JOYSTICK_") and not key:find("_LAST$") and not key:find("_FIRST$") and not key:find("_COUNT$") then
|
|
enums[val] = key:lower()
|
|
enums2[enums[val]] = val
|
|
end
|
|
end
|
|
end
|
|
|
|
pac.key_enums = enums
|
|
|
|
--TODO: Rate limit!!!
|
|
net.Receive("pac.BroadcastPlayerButton", function()
|
|
local ply = net.ReadEntity()
|
|
|
|
if not ply:IsValid() then return end
|
|
|
|
if ply == pac.LocalPlayer and (pace and pace.IsFocused() or gui.IsConsoleVisible()) then return end
|
|
|
|
local key = net.ReadUInt(8)
|
|
local down = net.ReadBool()
|
|
|
|
key = pac.key_enums[key] or key
|
|
|
|
ply.pac_buttons = ply.pac_buttons or {}
|
|
ply.pac_buttons[key] = down
|
|
end)
|
|
|
|
PART.OldEvents.button = {
|
|
arguments = {{button = "string"}},
|
|
userdata = {{enums = function()
|
|
return enums
|
|
end}},
|
|
nice = function(self, ent, button)
|
|
local ply = self:GetPlayerOwner()
|
|
|
|
local active = {}
|
|
if ply.pac_buttons then
|
|
for k,v in pairs(ply.pac_buttons) do
|
|
if v then
|
|
table.insert(active, "\"" .. tostring(k) .. "\"")
|
|
end
|
|
end
|
|
end
|
|
active = table.concat(active, " or ")
|
|
|
|
if active == "" then
|
|
active = "-"
|
|
end
|
|
|
|
return self:GetOperator() .. " \"" .. button .. "\"" .. " in (" .. active .. ")"
|
|
end,
|
|
callback = function(self, ent, button)
|
|
local ply = self:GetPlayerOwner()
|
|
|
|
if ply == pac.LocalPlayer then
|
|
ply.pac_broadcast_buttons = ply.pac_broadcast_buttons or {}
|
|
if not ply.pac_broadcast_buttons[button] then
|
|
local val = enums2[button:lower()]
|
|
if val then
|
|
net.Start("pac.AllowPlayerButtons")
|
|
net.WriteUInt(val, 8)
|
|
net.SendToServer()
|
|
end
|
|
ply.pac_broadcast_buttons[button] = true
|
|
end
|
|
end
|
|
|
|
local buttons = ply.pac_buttons
|
|
|
|
if buttons then
|
|
return buttons[button]
|
|
end
|
|
end,
|
|
}
|
|
end
|
|
|
|
do
|
|
local eventMeta = {}
|
|
|
|
eventMeta.__name = 'undefined'
|
|
AccessorFunc(eventMeta, '__name', 'Name')
|
|
AccessorFunc(eventMeta, '__name', 'EventName')
|
|
AccessorFunc(eventMeta, '__name', 'Nick')
|
|
|
|
function eventMeta:IsValid(event)
|
|
return true
|
|
end
|
|
|
|
function eventMeta:IsAvailable(eventPart)
|
|
return true
|
|
end
|
|
|
|
function eventMeta:GetArguments()
|
|
self.__registeredArguments = self.__registeredArguments or {}
|
|
return self.__registeredArguments
|
|
end
|
|
|
|
function eventMeta:AppendArgument(keyName, keyType, userdata)
|
|
self.__registeredArguments = self.__registeredArguments or {}
|
|
if not keyType then
|
|
error('No Type of argument was specified!')
|
|
end
|
|
|
|
if keyType ~= 'number' and keyType ~= 'string' and keyType ~= 'boolean' then
|
|
error('Invalid Type of argument was passed. Valids are number, string or boolean')
|
|
end
|
|
|
|
for i, data in ipairs(self.__registeredArguments) do
|
|
if data[1] == keyName then
|
|
error('Argument with key ' .. keyName .. ' already exists!')
|
|
end
|
|
end
|
|
|
|
self.__registeredArguments = self.__registeredArguments or {}
|
|
table.insert(self.__registeredArguments, {keyName, keyType, userdata})
|
|
end
|
|
|
|
function eventMeta:PopArgument(keyName)
|
|
for i, data in ipairs(self.__registeredArguments) do
|
|
if data[1] == keyName then
|
|
return true, i, table.remove(self.__registeredArguments, i)
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
eventMeta.RemoveArgument = eventMeta.PopArgument
|
|
eventMeta.SpliceArgument = eventMeta.PopArgument
|
|
|
|
function eventMeta:GetClass()
|
|
return self.__classname
|
|
end
|
|
|
|
function eventMeta:Think(event, ent, ...)
|
|
return false
|
|
end
|
|
|
|
function eventMeta:GetNiceName(part, ent)
|
|
if self.extra_nice_name then
|
|
return self.extra_nice_name(part, ent, part:GetParsedArgumentsForObject(self))
|
|
end
|
|
|
|
local str = part:GetEvent()
|
|
|
|
if part:GetArguments() ~= "" then
|
|
local args = part:GetArguments():gsub(";", " or ")
|
|
|
|
if not tonumber(args) then
|
|
args = [["]] .. args .. [["]]
|
|
end
|
|
str = str .. " " .. part:GetOperator() .. " " .. args
|
|
end
|
|
|
|
return pac.PrettifyName(str)
|
|
end
|
|
|
|
local eventMetaTable = {
|
|
__index = function(self, key)
|
|
if key == '__class' or key == '__classname' then
|
|
return rawget(getmetatable(self), '__classname')
|
|
end
|
|
|
|
if rawget(self, key) ~= nil then
|
|
return rawget(self, key)
|
|
end
|
|
|
|
return eventMeta[key]
|
|
end,
|
|
|
|
__call = function(self)
|
|
local newObj = pac.CreateEvent(self:GetClass())
|
|
|
|
for k, v in pairs(self) do
|
|
if not istable(v) then
|
|
newObj[k] = v
|
|
else
|
|
newObj[k] = table.Copy(v)
|
|
end
|
|
end
|
|
|
|
return newObj
|
|
end,
|
|
|
|
-- __newindex = function(self, key, val)
|
|
-- rawset(self, key, val)
|
|
-- end
|
|
}
|
|
|
|
function pac.GetEventMetatable()
|
|
return eventMeta
|
|
end
|
|
|
|
function pac.CreateEvent(nClassName, defArguments)
|
|
if not nClassName then error('No classname was specified!') end
|
|
|
|
local newObj = setmetatable({}, {
|
|
__index = eventMetaTable.__index,
|
|
__call = eventMetaTable.__call,
|
|
__classname = nClassName
|
|
})
|
|
|
|
newObj.__registeredArguments = {}
|
|
newObj:SetName(nClassName)
|
|
|
|
if defArguments then
|
|
for i, data in pairs(defArguments) do
|
|
newObj:AppendArgument(data[1], data[2], data[3])
|
|
end
|
|
end
|
|
|
|
return newObj
|
|
end
|
|
|
|
function pac.RegisterEvent(nRegister)
|
|
local classname = nRegister:GetClass()
|
|
|
|
if PART.Events[classname] then
|
|
pac.Message('WARN: Registering event with already existing classname!: '.. classname)
|
|
end
|
|
|
|
PART.Events[classname] = nRegister
|
|
end
|
|
|
|
for classname, data in pairs(PART.OldEvents) do
|
|
local arguments = data.arguments
|
|
local think = data.callback
|
|
local eventObject = pac.CreateEvent(classname)
|
|
|
|
if arguments then
|
|
for i, data2 in ipairs(arguments) do
|
|
local key, Type = next(data2)
|
|
eventObject:AppendArgument(key, Type, data.userdata and data.userdata[i] or nil)
|
|
end
|
|
end
|
|
|
|
eventObject.extra_nice_name = data.nice
|
|
|
|
function eventObject:Think(event, ent, ...)
|
|
return think(event, ent, ...)
|
|
end
|
|
|
|
pac.RegisterEvent(eventObject)
|
|
end
|
|
|
|
timer.Simple(0, function() -- After all addons has loaded
|
|
hook.Call('PAC3RegisterEvents', nil, pac.CreateEvent, pac.RegisterEvent)
|
|
end)
|
|
end
|
|
|
|
-- custom animation event
|
|
do
|
|
local animations = pac.animations
|
|
local event = {
|
|
name = "custom_animation_frame",
|
|
nice = function(self, ent, animation)
|
|
if animation == "" then self:SetWarning("no animation selected") return "no animation" end
|
|
local part = pac.GetLocalPart(animation)
|
|
if not IsValid(part) then self:SetError("invalid animation selected") return "invalid animation" end
|
|
self:SetWarning()
|
|
return part:GetName()
|
|
end,
|
|
args = {
|
|
{"animation", "string", {
|
|
enums = function(part)
|
|
local output = {}
|
|
local parts = pac.GetLocalParts()
|
|
|
|
for i, part in pairs(parts) do
|
|
if part.ClassName == "custom_animation" then
|
|
output[i] = part
|
|
end
|
|
end
|
|
|
|
return output
|
|
end
|
|
}},
|
|
{"frame_start", "number", {
|
|
editor_onchange = function(self, num)
|
|
local anim = pace.current_part:GetProperty("animation")
|
|
if anim ~= "" then
|
|
local part = pac.GetLocalPart(anim)
|
|
-- GetAnimationDuration only works while editor is active for some reason
|
|
local data = util.JSONToTable(part:GetData())
|
|
return math.Clamp(math.ceil(num), 1, #data.FrameData)
|
|
end
|
|
end
|
|
}},
|
|
{"frame_end", "number", {
|
|
editor_onchange = function(self, num)
|
|
local anim = pace.current_part:GetProperty("animation")
|
|
local start = pace.current_part:GetProperty("frame_start")
|
|
if anim ~= "" then
|
|
local part = pac.GetLocalPart(anim)
|
|
-- GetAnimationDuration only works while editor is active for some reason
|
|
local data = util.JSONToTable(part:GetData())
|
|
return math.Clamp(math.ceil(num), start, #data.FrameData)
|
|
end
|
|
end
|
|
}},
|
|
--{"framedelta", "number", {editor_clamp = {0,1}, editor_sensitivity = 0.15}}
|
|
},
|
|
available = function(self, eventPart)
|
|
return next(animations.registered) and true or false
|
|
end,
|
|
func = function (self, eventPart, ent, animation, frame_start, frame_end)
|
|
local frame_start = frame_start or 1
|
|
local frame_end = frame_end or 1
|
|
if not animation or animation == "" then return end
|
|
if not IsValid(ent) then return end
|
|
if not next(animations.playing) then return end
|
|
for i,v in ipairs(animations.playing) do
|
|
if v == ent then
|
|
local part = pac.GetPartFromUniqueID(pac.Hash(ent), animation)
|
|
if not IsValid(part) then return end
|
|
local frame, delta = animations.GetEntityAnimationFrame(ent, part:GetAnimID())
|
|
if not frame or not delta then return end -- different animation part is playing
|
|
return frame >= frame_start and frame <= frame_end
|
|
end
|
|
end
|
|
end
|
|
}
|
|
|
|
local eventObject = pac.CreateEvent(event.name, event.args)
|
|
eventObject.Think = event.func
|
|
eventObject.IsAvailable = event.available
|
|
eventObject.extra_nice_name = event.nice
|
|
|
|
pac.RegisterEvent(eventObject)
|
|
end
|
|
|
|
-- DarkRP default events
|
|
do
|
|
local plyMeta = FindMetaTable('Player')
|
|
local gamemode = engine.ActiveGamemode
|
|
local isDarkRP = function() return gamemode() == 'darkrp' end
|
|
|
|
local events = {
|
|
{
|
|
name = 'is_arrested',
|
|
args = {},
|
|
available = function() return plyMeta.isArrested ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.isArrested and ent:isArrested() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'is_wanted',
|
|
args = {},
|
|
available = function() return plyMeta.isWanted ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.isWanted and ent:isWanted() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'is_police',
|
|
args = {},
|
|
available = function() return plyMeta.isCP ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.isCP and ent:isCP() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'wanted_reason',
|
|
args = {{'find', 'string'}},
|
|
available = function() return plyMeta.getWantedReason ~= nil and plyMeta.isWanted ~= nil end,
|
|
func = function(self, eventPart, ent, find)
|
|
ent = try_viewmodel(ent)
|
|
return eventPart:StringOperator(ent.isWanted and ent.getWantedReason and ent:isWanted() and ent:getWantedReason() or '', find)
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'is_cook',
|
|
args = {},
|
|
available = function() return plyMeta.isCook ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.isCook and ent:isCook() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'is_hitman',
|
|
args = {},
|
|
available = function() return plyMeta.isHitman ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.isHitman and ent:isHitman() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'has_hit',
|
|
args = {},
|
|
available = function() return plyMeta.hasHit ~= nil end,
|
|
func = function(self, eventPart, ent)
|
|
ent = try_viewmodel(ent)
|
|
return ent.hasHit and ent:hasHit() or false
|
|
end
|
|
},
|
|
|
|
{
|
|
name = 'hit_price',
|
|
args = {{'amount', 'number'}},
|
|
available = function() return plyMeta.getHitPrice ~= nil end,
|
|
func = function(self, eventPart, ent, amount)
|
|
ent = try_viewmodel(ent)
|
|
return eventPart:NumberOperator(ent.getHitPrice and ent:getHitPrice() or 0, amount)
|
|
end
|
|
},
|
|
}
|
|
|
|
for k, v in ipairs(events) do
|
|
local available = v.available
|
|
local eventObject = pac.CreateEvent(v.name, v.args)
|
|
eventObject.Think = v.func
|
|
|
|
function eventObject:IsAvailable()
|
|
return isDarkRP() and available()
|
|
end
|
|
|
|
pac.RegisterEvent(eventObject)
|
|
end
|
|
end
|
|
|
|
function PART:GetParentEx()
|
|
local parent = self:GetTargetPart()
|
|
|
|
if parent:IsValid() then
|
|
return parent
|
|
end
|
|
|
|
return self:GetParent()
|
|
end
|
|
|
|
function PART:GetNiceName()
|
|
local event_name = self:GetEvent()
|
|
|
|
if not PART.Events[event_name] then return "unknown event" end
|
|
|
|
return PART.Events[event_name]:GetNiceName(self, get_owner(self))
|
|
end
|
|
|
|
local function is_hidden_by_something_else(part, ignored_part)
|
|
if part.active_events_ref_count > 0 and not part.active_events[ignored_part] then
|
|
return true
|
|
end
|
|
|
|
return part.Hide
|
|
end
|
|
|
|
function PART:IsHiddenBySomethingElse(only_self)
|
|
if is_hidden_by_something_else(self, self) then
|
|
return true
|
|
end
|
|
|
|
if only_self then return false end
|
|
|
|
for _, parent in ipairs(self:GetParentList()) do
|
|
if is_hidden_by_something_else(parent, self) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function should_trigger(self, ent, eventObject)
|
|
if not eventObject:IsAvailable(self) then
|
|
return true
|
|
end
|
|
|
|
local b = false
|
|
if eventObject.ParseArguments then
|
|
b = eventObject:Think(self, ent, eventObject:ParseArguments(self)) or false
|
|
else
|
|
b = eventObject:Think(self, ent, self:GetParsedArgumentsForObject(eventObject)) or false
|
|
end
|
|
|
|
if self.Invert then
|
|
b = not b
|
|
end
|
|
|
|
if is_hidden_by_something_else(self, self) then
|
|
b = self.Invert
|
|
end
|
|
|
|
self.is_active = b
|
|
|
|
return b
|
|
end
|
|
|
|
PART.last_event_triggered = false
|
|
|
|
function PART:OnThink()
|
|
local ent = get_owner(self)
|
|
if not ent:IsValid() then return end
|
|
|
|
local data = PART.Events[self.Event]
|
|
if not data then return end
|
|
|
|
self:TriggerEvent(should_trigger(self, ent, data))
|
|
|
|
if pace and pace.IsActive() and self.Name == "" then
|
|
if self.pace_properties and self.pace_properties["Name"] and self.pace_properties["Name"]:IsValid() then
|
|
self.pace_properties["Name"]:SetText(self:GetNiceName())
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function PART:TriggerEvent(b)
|
|
self.event_triggered = b -- event_triggered is just used for the editor
|
|
|
|
if self.AffectChildrenOnly then
|
|
for _, child in ipairs(self:GetChildren()) do
|
|
child:SetEventTrigger(self, b)
|
|
end
|
|
else
|
|
local parent = self:GetParent()
|
|
if parent:IsValid() then
|
|
parent:SetEventTrigger(self, b)
|
|
end
|
|
end
|
|
end
|
|
|
|
PART.Operators = {
|
|
"equal",
|
|
"not equal",
|
|
"above",
|
|
"equal or above",
|
|
"below",
|
|
"equal or below",
|
|
|
|
"find",
|
|
"find simple",
|
|
|
|
"maybe",
|
|
}
|
|
|
|
pac.EventArgumentCache = {}
|
|
|
|
function PART:ParseArguments(...)
|
|
local str = ""
|
|
local args = {...}
|
|
|
|
for key, val in pairs(args) do
|
|
local T = type(val)
|
|
|
|
if T == "boolean" then
|
|
val = val and "1" or "0"
|
|
elseif T == "string" then
|
|
val = tostring(val) or ""
|
|
elseif T == "number" then
|
|
val = tostring(val) or "0"
|
|
end
|
|
|
|
if key == #args then
|
|
str = str .. val
|
|
else
|
|
str = str .. val .. "@@"
|
|
end
|
|
end
|
|
|
|
self.Arguments = str
|
|
end
|
|
|
|
function PART:GetParsedArguments(eventObject)
|
|
if not eventObject then return end
|
|
|
|
if eventObject.ParseArguments then
|
|
return eventObject:ParseArguments(self)
|
|
end
|
|
|
|
return self:GetParsedArgumentsForObject(eventObject)
|
|
end
|
|
|
|
function PART:GetParsedArgumentsForObject(eventObject)
|
|
if not eventObject then return end
|
|
|
|
local line = self.Arguments
|
|
local hash = line .. tostring(eventObject)
|
|
|
|
if pac.EventArgumentCache[hash] then
|
|
return unpack(pac.EventArgumentCache[hash])
|
|
end
|
|
|
|
local args = line:Split("@@")
|
|
|
|
for i, argData in pairs(eventObject:GetArguments()) do
|
|
local typ = argData[2]
|
|
|
|
if args[i] ~= nil then
|
|
if typ == "boolean" then
|
|
args[i] = tonumber(args[i]) ~= 0
|
|
elseif typ == "number" then
|
|
args[i] = tonumber(args[i]) or 0
|
|
elseif typ == "string" then
|
|
args[i] = tostring(args[i]) or ""
|
|
end
|
|
end
|
|
end
|
|
|
|
pac.EventArgumentCache[hash] = args
|
|
|
|
return unpack(args)
|
|
end
|
|
|
|
local cache = {}
|
|
|
|
local function CompareBTable(a, btbl, func, ...)
|
|
for _, b in pairs(btbl) do
|
|
if func(a, b, ...) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function PART:StringOperator(a, b)
|
|
|
|
local args = cache[b]
|
|
|
|
if not args then
|
|
args = b:Split(";")
|
|
cache[b] = args
|
|
end
|
|
|
|
if not self.Operator or not a or not b then
|
|
return false
|
|
elseif self.Operator == "equal" then
|
|
return CompareBTable(a, args, function(x, y) return x == y end)
|
|
elseif self.Operator == "not equal" then
|
|
return CompareBTable(a, args, function(x, y) return x ~= y end)
|
|
elseif self.Operator == "find" then
|
|
return CompareBTable(a, args, pac.StringFind)
|
|
elseif self.Operator == "find simple" then
|
|
return CompareBTable(a, args, pac.StringFind, true)
|
|
elseif self.Operator == "changed" then
|
|
if a ~= self.changed_last_a then
|
|
self.changed_last_a = a
|
|
|
|
return true
|
|
end
|
|
elseif self.Operator == "maybe" then
|
|
return math.random() > 0.5
|
|
end
|
|
end
|
|
|
|
function PART:NumberOperator(a, b)
|
|
if not self.Operator or not a or not b then
|
|
return false
|
|
elseif self.Operator == "equal" then
|
|
return a == b
|
|
elseif self.Operator == "not equal" then
|
|
return a ~= b
|
|
elseif self.Operator == "above" then
|
|
return a > b
|
|
elseif self.Operator == "equal or above" then
|
|
return a >= b
|
|
elseif self.Operator == "below" then
|
|
return a < b
|
|
elseif self.Operator == "equal or below" then
|
|
return a <= b
|
|
elseif self.Operator == "maybe" then
|
|
return math.random() > 0.5
|
|
end
|
|
end
|
|
|
|
function PART:OnHide()
|
|
if self.timerx_reset then
|
|
self.time = nil
|
|
self.number = 0
|
|
end
|
|
|
|
if self.Event == "weapon_class" then
|
|
local ent = self:GetOwner()
|
|
if ent:IsValid() then
|
|
ent = ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
|
if ent:IsValid() then
|
|
ent.pac_weapon_class = nil
|
|
ent:SetNoDraw(false)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:OnShow()
|
|
if self.timerx_reset then
|
|
self.time = nil
|
|
self.number = 0
|
|
end
|
|
end
|
|
|
|
function PART:OnAnimationEvent(ent)
|
|
if self.Event == "animation_event" then
|
|
self:GetParent():CallRecursive("Think")
|
|
end
|
|
end
|
|
|
|
function PART:OnFireBullets()
|
|
if self.Event == "fire_bullets" then
|
|
self:GetParent():CallRecursive("Think")
|
|
end
|
|
end
|
|
|
|
function PART:OnEmitSound(ent)
|
|
if self.Event == "emit_sound" then
|
|
self:GetParent():CallRecursive("Think")
|
|
|
|
if ent.pac_emit_sound.mute_me then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
BUILDER:Register()
|
|
|
|
do
|
|
local enums = {}
|
|
|
|
for key, val in pairs(_G) do
|
|
if isstring(key) and key:find("PLAYERANIMEVENT_", nil, true) then
|
|
enums[val] = key:gsub("PLAYERANIMEVENT_", ""):gsub("_", " "):lower()
|
|
end
|
|
end
|
|
|
|
pac.AddHook("DoAnimationEvent", "animation_events", function(ply, event, data)
|
|
-- update all parts once so OnShow and OnHide are updated properly for animation events
|
|
if ply.pac_has_parts then
|
|
ply.pac_anim_event = {name = enums[event], time = pac.RealTime, reset = true}
|
|
|
|
pac.CallRecursiveOnAllParts("OnAnimationEvent")
|
|
end
|
|
end)
|
|
end
|
|
|
|
|
|
pac.AddHook("EntityEmitSound", "emit_sound", function(data)
|
|
if pac.playing_sound then return end
|
|
local ent = data.Entity
|
|
|
|
if not ent:IsValid() or not ent.pac_has_parts then return end
|
|
|
|
ent.pac_emit_sound = {name = data.SoundName, time = pac.RealTime, reset = true, mute_me = ent.pac_emit_sound and ent.pac_emit_sound.mute_me or false}
|
|
|
|
if pac.CallRecursiveOnAllParts("OnEmitSound", ent) == false then
|
|
return false
|
|
end
|
|
|
|
if ent.pac_mute_sounds then
|
|
return false
|
|
end
|
|
end)
|
|
|
|
pac.AddHook("EntityFireBullets", "firebullets", function(ent, data)
|
|
if not ent:IsValid() or not ent.pac_has_parts then return end
|
|
ent.pac_fire_bullets = {name = data.AmmoType, time = pac.RealTime, reset = true}
|
|
|
|
pac.CallRecursiveOnAllParts("OnFireBullets")
|
|
|
|
if ent.pac_hide_bullets then
|
|
return false
|
|
end
|
|
end)
|
|
|
|
net.Receive("pac_event", function(umr)
|
|
local ply = net.ReadEntity()
|
|
local str = net.ReadString()
|
|
local on = net.ReadInt(8)
|
|
|
|
-- ^ resets all other events
|
|
if str:find("^", 0, true) then
|
|
ply.pac_command_events = {}
|
|
end
|
|
|
|
if ply:IsValid() then
|
|
ply.pac_command_events = ply.pac_command_events or {}
|
|
ply.pac_command_events[str] = {name = str, time = pac.RealTime, on = on}
|
|
end
|
|
end)
|
|
|
|
pac.AddHook("OnPlayerChat", "say_event", function(ply, str)
|
|
if ply:IsValid() then
|
|
ply.pac_say_event = {str = str, time = pac.RealTime}
|
|
end
|
|
end)
|
|
|
|
pac.AddHook("GravGunOnPickedUp", "gravgun_event", function(ply, ent)
|
|
if ply:IsValid() then
|
|
ply.pac_gravgun_ent = ent
|
|
end
|
|
end)
|
|
|
|
pac.AddHook("GravGunOnDropped", "gravgun_event", function(ply, ent)
|
|
if ply:IsValid() then
|
|
ply.pac_gravgun_ent = ent
|
|
end
|
|
end)
|
|
-- ####
|
|
|
|
pac.AddHook("GravGunPunt", "gravgun_event", function(ply, ent)
|
|
if ply:IsValid() then
|
|
ply.pac_gravgun_ent = ent
|
|
ply.pac_gravgun_punt = pac.RealTime
|
|
end
|
|
end)
|
|
|
|
--[[
|
|
attack primary
|
|
swim
|
|
flinch rightleg
|
|
flinch leftarm
|
|
flinch head
|
|
cancel
|
|
attack secondary
|
|
flinch rightarm
|
|
jump
|
|
snap yaw
|
|
attack grenade
|
|
custom
|
|
cancel reload
|
|
reload loop
|
|
custom gesture sequence
|
|
custom sequence
|
|
spawn
|
|
doublejump
|
|
flinch leftleg
|
|
flinch chest
|
|
die
|
|
reload end
|
|
reload
|
|
custom gesture
|
|
--]]
|
|
|
|
|
|
-- Custom event selector wheel
|
|
do
|
|
local function get_events()
|
|
local available = {}
|
|
|
|
for k,v in pairs(pac.GetLocalParts()) do
|
|
if v.ClassName == "event" then
|
|
local e = v:GetEvent()
|
|
if e == "command" then
|
|
local cmd, time, hide = v:GetParsedArgumentsForObject(v.Events.command)
|
|
if hide then continue end
|
|
|
|
available[cmd] = {type = e, time = time}
|
|
end
|
|
end
|
|
end
|
|
|
|
local list = {}
|
|
for k,v in pairs(available) do
|
|
v.trigger = k
|
|
table.insert(list, v)
|
|
end
|
|
|
|
table.sort(list, function(a, b) return a.trigger > b.trigger end)
|
|
|
|
return list
|
|
end
|
|
|
|
local selectorBg = Material("sgm/playercircle")
|
|
local selected
|
|
|
|
function pac.openEventSelectionWheel()
|
|
gui.EnableScreenClicker(true)
|
|
|
|
local scrw, scrh = ScrW(), ScrH()
|
|
local scrw2, scrh2 = scrw*0.5, scrh*0.5
|
|
local color_red = Color(255,0,0)
|
|
local R = 48
|
|
|
|
local events = get_events()
|
|
local nevents = #events
|
|
|
|
-- Theta size of each wedge
|
|
local thetadiff = math.pi*2 / nevents
|
|
-- Used to compare the dot product
|
|
local coslimit = math.cos(thetadiff * 0.5)
|
|
-- Keeps the circles R units from each others' center
|
|
local radius
|
|
if nevents < 3 then
|
|
radius = R
|
|
else
|
|
radius = R/math.cos((nevents - 2)*math.pi*0.5/nevents)
|
|
end
|
|
|
|
-- Scale down to keep from going out of the screen
|
|
local gScale
|
|
if radius+R > scrh2 then
|
|
gScale = scrh2 / (radius+R)
|
|
else
|
|
gScale = 1
|
|
end
|
|
|
|
local selections = {}
|
|
for k, v in ipairs(events) do
|
|
local theta = (k-1)*thetadiff
|
|
selections[k] = {
|
|
grow = 0,
|
|
name = v.trigger,
|
|
event = v,
|
|
x = math.sin(theta),
|
|
y = -math.cos(theta),
|
|
}
|
|
end
|
|
|
|
local function draw_circle(self, x, y)
|
|
local dot = self.x*x + self.y*y
|
|
local grow
|
|
if dot > coslimit then
|
|
selected = self
|
|
grow = 0.1
|
|
else
|
|
grow = 0
|
|
end
|
|
self.grow = self.grow*0.9 + grow -- Framerate will affect this effect's speed but oh well
|
|
|
|
local scale = gScale*(1 + self.grow*0.2)
|
|
local m = Matrix()
|
|
m:SetTranslation(Vector(scrw2, scrh2, 0))
|
|
m:Scale(Vector(scale, scale, scale))
|
|
cam.PushModelMatrix(m)
|
|
|
|
local x, y = self.x*radius, self.y*radius
|
|
|
|
|
|
local ply = pac.LocalPlayer
|
|
local data = ply.pac_command_events and ply.pac_command_events[self.event.trigger] and ply.pac_command_events[self.event.trigger]
|
|
if data then
|
|
local is_oneshot = self.event.time and self.event.time > 0
|
|
|
|
if is_oneshot then
|
|
local f = (pac.RealTime - data.time) / self.event.time
|
|
local s = Lerp(math.Clamp(f,0,1), 1, 0)
|
|
local v = Lerp(math.Clamp(f,0,1), 0.55, 0.15)
|
|
surface.SetDrawColor(HSVToColor(210,s,v))
|
|
else
|
|
if data.on == 1 then
|
|
surface.SetDrawColor(HSVToColor(210,1,0.55))
|
|
else
|
|
surface.SetDrawColor(HSVToColor(210,0,0.15))
|
|
end
|
|
end
|
|
else
|
|
surface.SetDrawColor(HSVToColor(210,0,0.15))
|
|
end
|
|
|
|
surface.DrawTexturedRect(x-48, y-48, 96, 96)
|
|
draw.SimpleText(self.name, "DermaDefault", x, y, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
|
|
|
|
cam.PopModelMatrix()
|
|
end
|
|
|
|
pac.AddHook("HUDPaint","custom_event_selector",function()
|
|
-- Right clicking cancels
|
|
if input.IsButtonDown(MOUSE_RIGHT) then pac.closeEventSelectionWheel(true) return end
|
|
|
|
-- Normalize mouse vector from center of screen
|
|
local x, y = input.GetCursorPos()
|
|
x = x - scrw2
|
|
y = y - scrh2
|
|
if x==0 and y==0 then x = 1 y = 0 else
|
|
local l = math.sqrt(x^2+y^2)
|
|
x = x/l
|
|
y = y/l
|
|
end
|
|
|
|
DisableClipping(true)
|
|
render.PushFilterMag(TEXFILTER.ANISOTROPIC)
|
|
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
|
|
|
|
surface.SetMaterial(selectorBg)
|
|
|
|
draw.SimpleText("Right click to cancel", "DermaDefault", scrw2, scrh2+radius+R, color_red, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
|
|
for _, v in ipairs(selections) do draw_circle(v, x, y) end
|
|
|
|
render.PopFilterMag()
|
|
render.PopFilterMin()
|
|
DisableClipping(false)
|
|
end)
|
|
end
|
|
|
|
function pac.closeEventSelectionWheel(cancel)
|
|
gui.EnableScreenClicker(false)
|
|
pac.RemoveHook("HUDPaint","custom_event_selector")
|
|
|
|
if selected and cancel ~= true then
|
|
if not selected.event.time then
|
|
RunConsoleCommand("pac_event", selected.event.trigger, "toggle")
|
|
elseif selected.event.time > 0 then
|
|
RunConsoleCommand("pac_event", selected.event.trigger)
|
|
else
|
|
local ply = pac.LocalPlayer
|
|
|
|
if ply.pac_command_events and ply.pac_command_events[selected.event.trigger] and ply.pac_command_events[selected.event.trigger].on == 1 then
|
|
RunConsoleCommand("pac_event", selected.event.trigger, "0")
|
|
else
|
|
RunConsoleCommand("pac_event", selected.event.trigger, "1")
|
|
end
|
|
end
|
|
end
|
|
selected = nil
|
|
end
|
|
|
|
concommand.Add("+pac_events", pac.openEventSelectionWheel)
|
|
concommand.Add("-pac_events", pac.closeEventSelectionWheel)
|
|
end
|