Physgun Wiki

Как написан SWEP ключей

Система дверей хранит владение, но не отпирает и не запирает двери сама: это делает оружие entities/weapons/keys.lua через ENTITY:CanBeOpenedBy и ent:Fire("lock"/"unlock").

1. Логика замка

ЛКМ запирает, ПКМ отпирает, обе кнопки вызывают один и тот же метод ToggleDoor:

function SWEP:PrimaryAttack() self:SetNextPrimaryFire(CurTime() + 1) self:ToggleDoor("lock", false) end function SWEP:SecondaryAttack() self:SetNextSecondaryFire(CurTime() + 1) self:ToggleDoor("unlock", true) end function SWEP:ToggleDoor(state, hard) local ply = self:GetOwner() local tr = ply:GetEyeTrace() local door = tr.Entity if not IsValid(door) or not door:IsDoor() then return end if ply:GetShootPos():Distance(tr.HitPos) > self.DoorRange then return end if not door:CanBeOpenedBy(ply) then self:Knock(door, hard) return end if CLIENT then return end door:Fire(state) local partner = door:GetPartnerDoor() if IsValid(partner) then partner:Fire(state) end self:EmitSound("doors/door_latch3.wav") end

CanBeOpenedBy уже учитывает владельца, совладельцев, команду и профессию: оружие не дублирует эту логику. Двойные двери запираются вместе через ENTITY:GetPartnerDoor.

2. Стук по чужой двери

Если доступа нет, вместо Fire игрок «стучит»: проигрывается анимация руки (жёстче на ПКМ) и звук удара по двери с обеих сторон сети (клиент играет анимацию сразу, звук ставится на сервере с задержкой):

function SWEP:Knock(door, hard) if not IsFirstTimePredicted() then return end self.Idle = CurTime() + (self:PlayAnim(hard and "hard" or "soft") or 1) if CLIENT then return end local ply = self:GetOwner() if IsValid(ply) then ply:RunLuaAnimation(FRAMES) end for _, t in ipairs({0.2, 0.5}) do timer.Simple(t, function() if not IsValid(door) then return end door:EmitSound("physics/wood/wood_crate_impact_hard1.wav", 80, math.random(120, 175)) end) end end

ply:RunLuaAnimation(FRAMES) проигрывает покадровую анимацию руки на третьем лице через библиотеку LuaAnim (lua/autorun/animations.lua): FRAMES — таблица вида { {время, {кость = угол, ...}}, ... }, зарегистрированная заранее через LuaAnim.Register("keys_knock", FRAMES).

3. Анимации вьюмодели

hard/soft/idle — это секвенции вьюмодели (v_keys.mdl), проигрываются через SendViewModelMatchingSequence, не через стандартный SWEP:Deploy/анимации оружия:

function SWEP:PlayAnim(name) local vm = self:GetVM() if not IsValid(vm) then return end local seq = vm:LookupSequence(name) if seq < 0 then return end vm:SendViewModelMatchingSequence(seq) vm:SetPlaybackRate(1) return vm:SequenceDuration(seq) end

SWEP:Think следит за self.Idle (временем окончания текущей секвенции) и возвращает вьюмодель в idle, когда анимация доиграла.