add sborka
This commit is contained in:
139
garrysmod/gamemodes/helix/plugins/act/cl_hooks.lua
Normal file
139
garrysmod/gamemodes/helix/plugins/act/cl_hooks.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
local animationTime = 2
|
||||
|
||||
local PLUGIN = PLUGIN
|
||||
PLUGIN.cameraFraction = 0
|
||||
|
||||
local function GetHeadBone(client)
|
||||
local head
|
||||
|
||||
for i = 1, client:GetBoneCount() do
|
||||
local name = client:GetBoneName(i)
|
||||
|
||||
if (string.find(name:lower(), "head")) then
|
||||
head = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return head
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerBindPress(client, bind, bPressed)
|
||||
if (!client:GetNetVar("actEnterAngle")) then
|
||||
return
|
||||
end
|
||||
|
||||
if (bind:find("+jump") and bPressed) then
|
||||
ix.command.Send("ExitAct")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function PLUGIN:ShouldDrawLocalPlayer(client)
|
||||
if (client:GetNetVar("actEnterAngle") and self.cameraFraction > 0.25) then
|
||||
return true
|
||||
elseif (self.cameraFraction > 0.25) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local forwardOffset = 16
|
||||
local backwardOffset = -32
|
||||
local heightOffset = Vector(0, 0, 20)
|
||||
local idleHeightOffset = Vector(0, 0, 6)
|
||||
local traceMin = Vector(-4, -4, -4)
|
||||
local traceMax = Vector(4, 4, 4)
|
||||
|
||||
function PLUGIN:CalcView(client, origin)
|
||||
local enterAngle = client:GetNetVar("actEnterAngle")
|
||||
local fraction = self.cameraFraction
|
||||
local offset = self.bIdle and forwardOffset or backwardOffset
|
||||
local height = self.bIdle and idleHeightOffset or heightOffset
|
||||
|
||||
if (!enterAngle) then
|
||||
if (fraction > 0) then
|
||||
local view = {
|
||||
origin = LerpVector(fraction, origin, origin + self.forward * offset + height)
|
||||
}
|
||||
|
||||
if (self.cameraTween) then
|
||||
self.cameraTween:update(FrameTime())
|
||||
end
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local view = {}
|
||||
local forward = enterAngle:Forward()
|
||||
local head = GetHeadBone(client)
|
||||
|
||||
local bFirstPerson = true
|
||||
|
||||
if (ix.option.Get("thirdpersonEnabled", false)) then
|
||||
local originPosition = head and client:GetBonePosition(head) or client:GetPos()
|
||||
|
||||
-- check if the camera will hit something
|
||||
local data = util.TraceHull({
|
||||
start = originPosition,
|
||||
endpos = originPosition - client:EyeAngles():Forward() * 48,
|
||||
mins = traceMin * 0.75,
|
||||
maxs = traceMax * 0.75,
|
||||
filter = client
|
||||
})
|
||||
|
||||
bFirstPerson = data.Hit
|
||||
|
||||
if (!bFirstPerson) then
|
||||
view.origin = data.HitPos
|
||||
end
|
||||
end
|
||||
|
||||
if (bFirstPerson) then
|
||||
if (head) then
|
||||
local position = client:GetBonePosition(head) + forward * offset + height
|
||||
local data = {
|
||||
start = (client:GetBonePosition(head) or Vector(0, 0, 64)) + forward * 8,
|
||||
endpos = position + forward * offset,
|
||||
mins = traceMin,
|
||||
maxs = traceMax,
|
||||
filter = client
|
||||
}
|
||||
|
||||
data = util.TraceHull(data)
|
||||
|
||||
if (data.Hit) then
|
||||
view.origin = data.HitPos
|
||||
else
|
||||
view.origin = position
|
||||
end
|
||||
else
|
||||
view.origin = origin + forward * forwardOffset + height
|
||||
end
|
||||
end
|
||||
|
||||
view.origin = LerpVector(fraction, origin, view.origin)
|
||||
|
||||
if (self.cameraTween) then
|
||||
self.cameraTween:update(FrameTime())
|
||||
end
|
||||
|
||||
return view
|
||||
end
|
||||
|
||||
net.Receive("ixActEnter", function()
|
||||
PLUGIN.bIdle = net.ReadBool()
|
||||
PLUGIN.forward = LocalPlayer():GetNetVar("actEnterAngle"):Forward()
|
||||
PLUGIN.cameraTween = ix.tween.new(animationTime, PLUGIN, {
|
||||
cameraFraction = 1
|
||||
}, "outQuint")
|
||||
end)
|
||||
|
||||
net.Receive("ixActLeave", function()
|
||||
PLUGIN.cameraTween = ix.tween.new(animationTime * 0.5, PLUGIN, {
|
||||
cameraFraction = 0
|
||||
}, "outQuint")
|
||||
end)
|
||||
166
garrysmod/gamemodes/helix/plugins/act/sh_definitions.lua
Normal file
166
garrysmod/gamemodes/helix/plugins/act/sh_definitions.lua
Normal file
@@ -0,0 +1,166 @@
|
||||
|
||||
local function FacingWall(client)
|
||||
local data = {}
|
||||
data.start = client:EyePos()
|
||||
data.endpos = data.start + client:GetForward() * 20
|
||||
data.filter = client
|
||||
|
||||
if (!util.TraceLine(data).Hit) then
|
||||
return "@faceWall"
|
||||
end
|
||||
end
|
||||
|
||||
local function FacingWallBack(client)
|
||||
local data = {}
|
||||
data.start = client:LocalToWorld(client:OBBCenter())
|
||||
data.endpos = data.start - client:GetForward() * 20
|
||||
data.filter = client
|
||||
|
||||
if (!util.TraceLine(data).Hit) then
|
||||
return "@faceWallBack"
|
||||
end
|
||||
end
|
||||
|
||||
function PLUGIN:SetupActs()
|
||||
-- sit
|
||||
ix.act.Register("Sit", {"citizen_male", "citizen_female"}, {
|
||||
start = {"idle_to_sit_ground", "idle_to_sit_chair"},
|
||||
sequence = {"sit_ground", "sit_chair"},
|
||||
finish = {
|
||||
{"sit_ground_to_idle", duration = 2.1},
|
||||
""
|
||||
},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("SitWall", {"citizen_male", "citizen_female"}, {
|
||||
sequence = {
|
||||
{"plazaidle4", check = FacingWallBack},
|
||||
{"injured1", check = FacingWallBack, offset = function(client)
|
||||
return client:GetForward() * 14
|
||||
end}
|
||||
},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("Sit", "vortigaunt", {
|
||||
sequence = "chess_wait",
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
-- stand
|
||||
ix.act.Register("Stand", "citizen_male", {
|
||||
sequence = {"lineidle01", "lineidle02", "lineidle03", "lineidle04"},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("Stand", "citizen_female", {
|
||||
sequence = {"lineidle01", "lineidle02", "lineidle03"},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("Stand", "metrocop", {
|
||||
sequence = "plazathreat2"
|
||||
})
|
||||
|
||||
-- cheer
|
||||
ix.act.Register("Cheer", "citizen_male", {
|
||||
sequence = {{"cheer1", duration = 1.6}, "cheer2", "wave_smg1"}
|
||||
})
|
||||
|
||||
ix.act.Register("Cheer", "citizen_female", {
|
||||
sequence = {"cheer1", "wave_smg1"}
|
||||
})
|
||||
|
||||
-- lean
|
||||
ix.act.Register("Lean", {"citizen_male", "citizen_female"}, {
|
||||
start = {"idle_to_lean_back", "", ""},
|
||||
sequence = {
|
||||
{"lean_back", check = FacingWallBack},
|
||||
{"plazaidle1", check = FacingWallBack},
|
||||
{"plazaidle2", check = FacingWallBack}
|
||||
},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("Lean", {"metrocop"}, {
|
||||
sequence = {{"idle_baton", check = FacingWallBack}, "busyidle2"},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
-- injured
|
||||
ix.act.Register("Injured", "citizen_male", {
|
||||
sequence = {"d1_town05_wounded_idle_1", "d1_town05_wounded_idle_2", "d1_town05_winston_down"},
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
ix.act.Register("Injured", "citizen_female", {
|
||||
sequence = "d1_town05_wounded_idle_1",
|
||||
untimed = true,
|
||||
idle = true
|
||||
})
|
||||
|
||||
-- arrest
|
||||
ix.act.Register("ArrestWall", "citizen_male", {
|
||||
sequence = {
|
||||
{"apcarrestidle",
|
||||
check = FacingWall,
|
||||
offset = function(client)
|
||||
return -client:GetForward() * 23
|
||||
end},
|
||||
"spreadwallidle"
|
||||
},
|
||||
untimed = true
|
||||
})
|
||||
|
||||
ix.act.Register("Arrest", "citizen_male", {
|
||||
sequence = "arrestidle",
|
||||
untimed = true
|
||||
})
|
||||
|
||||
-- threat
|
||||
ix.act.Register("Threat", "metrocop", {
|
||||
sequence = "plazathreat1",
|
||||
})
|
||||
|
||||
-- deny
|
||||
ix.act.Register("Deny", "metrocop", {
|
||||
sequence = "harassfront2",
|
||||
})
|
||||
|
||||
-- motion
|
||||
ix.act.Register("Motion", "metrocop", {
|
||||
sequence = {"motionleft", "motionright", "luggagewarn"}
|
||||
})
|
||||
|
||||
-- wave
|
||||
ix.act.Register("Wave", {"citizen_male", "citizen_female"}, {
|
||||
sequence = {{"wave", duration = 2.75}, {"wave_close", duration = 1.75}}
|
||||
})
|
||||
|
||||
-- pant
|
||||
ix.act.Register("Pant", {"citizen_male", "citizen_female"}, {
|
||||
start = {"d2_coast03_postbattle_idle02_entry", "d2_coast03_postbattle_idle01_entry"},
|
||||
sequence = {"d2_coast03_postbattle_idle02", {"d2_coast03_postbattle_idle01", check = FacingWall}},
|
||||
untimed = true
|
||||
})
|
||||
|
||||
-- window
|
||||
ix.act.Register("Window", "citizen_male", {
|
||||
sequence = "d1_t03_tenements_look_out_window_idle",
|
||||
untimed = true
|
||||
})
|
||||
|
||||
ix.act.Register("Window", "citizen_female", {
|
||||
sequence = "d1_t03_lookoutwindow",
|
||||
untimed = true
|
||||
})
|
||||
end
|
||||
259
garrysmod/gamemodes/helix/plugins/act/sh_plugin.lua
Normal file
259
garrysmod/gamemodes/helix/plugins/act/sh_plugin.lua
Normal file
@@ -0,0 +1,259 @@
|
||||
|
||||
--[[--
|
||||
Provides players the ability to perform animations.
|
||||
|
||||
]]
|
||||
-- @module ix.act
|
||||
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
PLUGIN.name = "Player Acts"
|
||||
PLUGIN.description = "Adds animations that can be performed by certain models."
|
||||
PLUGIN.author = "`impulse"
|
||||
|
||||
ix.act = ix.act or {}
|
||||
ix.act.stored = ix.act.stored or {}
|
||||
|
||||
CAMI.RegisterPrivilege({
|
||||
Name = "Helix - Player Acts",
|
||||
MinAccess = "user"
|
||||
})
|
||||
|
||||
--- Registers a sequence as a performable animation.
|
||||
-- @realm shared
|
||||
-- @string name Name of the animation (in CamelCase)
|
||||
-- @string modelClass Model class to add this animation to
|
||||
-- @tab data An `ActInfoStructure` table describing the animation
|
||||
function ix.act.Register(name, modelClass, data)
|
||||
ix.act.stored[name] = ix.act.stored[name] or {} -- might be adding onto an existing act
|
||||
|
||||
if (!data.sequence) then
|
||||
return ErrorNoHalt(string.format(
|
||||
"Act '%s' for '%s' tried to register without a provided sequence\n", name, modelClass
|
||||
))
|
||||
end
|
||||
|
||||
if (!istable(data.sequence)) then
|
||||
data.sequence = {data.sequence}
|
||||
end
|
||||
|
||||
if (data.start and istable(data.start) and #data.start != #data.sequence) then
|
||||
return ErrorNoHalt(string.format(
|
||||
"Act '%s' tried to register without matching number of enter sequences\n", name
|
||||
))
|
||||
end
|
||||
|
||||
if (data.finish and istable(data.finish) and #data.finish != #data.sequence) then
|
||||
return ErrorNoHalt(string.format(
|
||||
"Act '%s' tried to register without matching number of exit sequences\n", name
|
||||
))
|
||||
end
|
||||
|
||||
if (istable(modelClass)) then
|
||||
for _, v in ipairs(modelClass) do
|
||||
ix.act.stored[name][v] = data
|
||||
end
|
||||
else
|
||||
ix.act.stored[name][modelClass] = data
|
||||
end
|
||||
end
|
||||
|
||||
--- Removes a sequence from being performable if it has been previously registered.
|
||||
-- @realm shared
|
||||
-- @string name Name of the animation
|
||||
function ix.act.Remove(name)
|
||||
ix.act.stored[name] = nil
|
||||
ix.command.list["Act" .. name] = nil
|
||||
end
|
||||
|
||||
ix.util.Include("sh_definitions.lua")
|
||||
ix.util.Include("sv_hooks.lua")
|
||||
ix.util.Include("cl_hooks.lua")
|
||||
|
||||
function PLUGIN:InitializedPlugins()
|
||||
hook.Run("SetupActs")
|
||||
hook.Run("PostSetupActs")
|
||||
end
|
||||
|
||||
function PLUGIN:ExitAct(client)
|
||||
client.ixUntimedSequence = nil
|
||||
client:SetNetVar("actEnterAngle")
|
||||
|
||||
net.Start("ixActLeave")
|
||||
net.Send(client)
|
||||
end
|
||||
|
||||
function PLUGIN:PostSetupActs()
|
||||
-- create chat commands for all stored acts
|
||||
for act, classes in pairs(ix.act.stored) do
|
||||
local variants = 1
|
||||
local COMMAND = {
|
||||
privilege = "Player Acts"
|
||||
}
|
||||
|
||||
-- check if this act has any variants (i.e /ActSit 2)
|
||||
for _, v in pairs(classes) do
|
||||
if (#v.sequence > 1) then
|
||||
variants = math.max(variants, #v.sequence)
|
||||
end
|
||||
end
|
||||
|
||||
-- setup command arguments if there are variants for this act
|
||||
if (variants > 1) then
|
||||
COMMAND.arguments = bit.bor(ix.type.number, ix.type.optional)
|
||||
COMMAND.argumentNames = {"variant (1-" .. variants .. ")"}
|
||||
end
|
||||
|
||||
COMMAND.GetDescription = function(command)
|
||||
return L("cmdAct", act)
|
||||
end
|
||||
|
||||
local privilege = "Helix - " .. COMMAND.privilege
|
||||
|
||||
-- we'll perform a model class check in OnCheckAccess to prevent the command from showing up on the client at all
|
||||
COMMAND.OnCheckAccess = function(command, client)
|
||||
local bHasAccess, _ = CAMI.PlayerHasAccess(client, privilege, nil)
|
||||
|
||||
if (!bHasAccess) then
|
||||
return false
|
||||
end
|
||||
|
||||
local modelClass = ix.anim.GetModelClass(client:GetModel())
|
||||
|
||||
if (!classes[modelClass]) then
|
||||
return false, "modelNoSeq"
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
COMMAND.OnRun = function(command, client, variant)
|
||||
variant = math.Clamp(tonumber(variant) or 1, 1, variants)
|
||||
|
||||
if (client:GetNetVar("actEnterAngle")) then
|
||||
return "@notNow"
|
||||
end
|
||||
|
||||
local modelClass = ix.anim.GetModelClass(client:GetModel())
|
||||
local bCanEnter, error = PLUGIN:CanPlayerEnterAct(client, modelClass, variant, classes)
|
||||
|
||||
if (!bCanEnter) then
|
||||
return error
|
||||
end
|
||||
|
||||
local data = classes[modelClass]
|
||||
local mainSequence = data.sequence[variant]
|
||||
local mainDuration
|
||||
|
||||
-- check if the main sequence has any extra info
|
||||
if (istable(mainSequence)) then
|
||||
-- any validity checks to perform (i.e facing a wall)
|
||||
if (mainSequence.check) then
|
||||
local result = mainSequence.check(client)
|
||||
|
||||
if (result) then
|
||||
return result
|
||||
end
|
||||
end
|
||||
|
||||
-- position offset
|
||||
if (mainSequence.offset) then
|
||||
client.ixOldPosition = client:GetPos()
|
||||
client:SetPos(client:GetPos() + mainSequence.offset(client))
|
||||
end
|
||||
|
||||
mainDuration = mainSequence.duration
|
||||
mainSequence = mainSequence[1]
|
||||
end
|
||||
|
||||
local startSequence = data.start and data.start[variant] or ""
|
||||
local startDuration
|
||||
|
||||
if (istable(startSequence)) then
|
||||
startDuration = startSequence.duration
|
||||
startSequence = startSequence[1]
|
||||
end
|
||||
|
||||
client:SetNetVar("actEnterAngle", client:GetAngles())
|
||||
|
||||
client:ForceSequence(startSequence, function()
|
||||
-- we've finished the start sequence
|
||||
client.ixUntimedSequence = data.untimed -- client can exit after the start sequence finishes playing
|
||||
|
||||
local duration = client:ForceSequence(mainSequence, function()
|
||||
-- we've stopped playing the main sequence (either duration expired or user cancelled the act)
|
||||
if (data.finish) then
|
||||
local finishSequence = data.finish[variant]
|
||||
local finishDuration
|
||||
|
||||
if (istable(finishSequence)) then
|
||||
finishDuration = finishSequence.duration
|
||||
finishSequence = finishSequence[1]
|
||||
end
|
||||
|
||||
client:ForceSequence(finishSequence, function()
|
||||
-- client has finished the end sequence and is no longer playing any animations
|
||||
self:ExitAct(client)
|
||||
end, finishDuration)
|
||||
else
|
||||
-- there's no end sequence so we can exit right away
|
||||
self:ExitAct(client)
|
||||
end
|
||||
end, data.untimed and 0 or (mainDuration or nil))
|
||||
|
||||
if (!duration) then
|
||||
-- the model doesn't support this variant
|
||||
self:ExitAct(client)
|
||||
client:NotifyLocalized("modelNoSeq")
|
||||
|
||||
return
|
||||
end
|
||||
end, startDuration, nil)
|
||||
|
||||
net.Start("ixActEnter")
|
||||
net.WriteBool(data.idle or false)
|
||||
net.Send(client)
|
||||
|
||||
client.ixNextAct = CurTime() + 4
|
||||
end
|
||||
|
||||
ix.command.Add("Act" .. act, COMMAND)
|
||||
end
|
||||
|
||||
-- setup exit act command
|
||||
local COMMAND = {
|
||||
privilege = "Player Acts",
|
||||
OnRun = function(command, client)
|
||||
if (client.ixUntimedSequence) then
|
||||
client:LeaveSequence()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
if (CLIENT) then
|
||||
-- hide this command from the command list
|
||||
COMMAND.OnCheckAccess = function(client)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
ix.command.Add("ExitAct", COMMAND)
|
||||
end
|
||||
|
||||
function PLUGIN:UpdateAnimation(client, moveData)
|
||||
local angle = client:GetNetVar("actEnterAngle")
|
||||
|
||||
if (angle) then
|
||||
client:SetRenderAngles(angle)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local keyBlacklist = IN_ATTACK + IN_ATTACK2
|
||||
|
||||
function PLUGIN:StartCommand(client, command)
|
||||
if (client:GetNetVar("actEnterAngle")) then
|
||||
command:RemoveKey(keyBlacklist)
|
||||
end
|
||||
end
|
||||
end
|
||||
52
garrysmod/gamemodes/helix/plugins/act/sv_hooks.lua
Normal file
52
garrysmod/gamemodes/helix/plugins/act/sv_hooks.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
local PLUGIN = PLUGIN
|
||||
|
||||
util.AddNetworkString("ixActEnter")
|
||||
util.AddNetworkString("ixActLeave")
|
||||
|
||||
function PLUGIN:CanPlayerEnterAct(client, modelClass, variant, act)
|
||||
if (!client:Alive() or client:GetLocalVar("ragdoll") or client:WaterLevel() > 0 or !client:IsOnGround()) then
|
||||
return false, L("notNow", client)
|
||||
end
|
||||
|
||||
-- check if player's model class has an entry in this act table
|
||||
modelClass = modelClass or ix.anim.GetModelClass(client:GetModel())
|
||||
local data = act[modelClass]
|
||||
|
||||
if (!data) then
|
||||
return false, L("modelNoSeq", client)
|
||||
end
|
||||
|
||||
-- some models don't support certain variants
|
||||
local sequence = data.sequence[variant]
|
||||
|
||||
if (!sequence) then
|
||||
return false, L("modelNoSeq", client)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerDeath(client)
|
||||
if (client.ixUntimedSequence) then
|
||||
client:SetNetVar("actEnterAngle")
|
||||
client:LeaveSequence()
|
||||
client.ixUntimedSequence = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PLUGIN:PlayerSpawn(client)
|
||||
if (client.ixUntimedSequence) then
|
||||
client:SetNetVar("actEnterAngle")
|
||||
client:LeaveSequence()
|
||||
client.ixUntimedSequence = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PLUGIN:OnCharacterFallover(client)
|
||||
if (client.ixUntimedSequence) then
|
||||
client:SetNetVar("actEnterAngle")
|
||||
client:LeaveSequence()
|
||||
client.ixUntimedSequence = nil
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user