2026-05-25 05:07:46 +00:00
-- здесь был BRAT.
2026-05-25 04:57:41 +00:00
MODULE = { }
MODULE.Model = " models/police.mdl "
MODULE.BoneList =
{
" ValveBiped.Bip01_Pelvis " ,
" ValveBiped.Bip01_Spine2 " ,
" ValveBiped.Bip01_Head1 " ,
" ValveBiped.Bip01_R_Upperarm " ,
" ValveBiped.Bip01_R_Forearm " ,
" ValveBiped.Bip01_L_Upperarm " ,
" ValveBiped.Bip01_L_Forearm " ,
}
local math_Clamp = math.Clamp
local math_Rand = math.Rand
local math_random = math.random
local table_HasValue = table.HasValue
local hand_offset = Vector ( 2 , 0 , 0 )
2026-05-25 05:07:46 +00:00
-- Twitch
2026-05-25 04:57:41 +00:00
local cv_twitch_enabled = CreateConVar ( " fedhoria_falling_twitch_enabled " , " 1 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Включить дергание для падающих торсов " )
local cv_twitch_interval_min = CreateConVar ( " fedhoria_falling_twitch_interval_min " , " 3 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Минимальный интервал между дерганиями (сек) " )
local cv_twitch_interval_max = CreateConVar ( " fedhoria_falling_twitch_interval_max " , " 6 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Максимальный интервал между дерганиями (сек) " )
local cv_twitch_force_min = CreateConVar ( " fedhoria_falling_twitch_min " , " 100 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Мин. угловая скорость для дергания " )
local cv_twitch_force_max = CreateConVar ( " fedhoria_falling_twitch_max " , " 250 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Макс. угловая скорость для дергания " )
local ignore_bone_indices_twitch = { 0 } -- игнор нахуй
2026-05-25 05:07:46 +00:00
-- Roll
2026-05-25 04:57:41 +00:00
local cv_anim_roll_enabled = CreateConVar ( " fedhoria_falling_anim_roll_enabled " , " 1 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Включить анимацию 'idleonfire' при ударе о землю " )
local cv_anim_roll_min_delay = CreateConVar ( " fedhoria_falling_anim_roll_min_delay " , " 0.5 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Мин. задержка перед возможной анимацией после удара (сек) " )
local cv_anim_roll_duration = CreateConVar ( " fedhoria_falling_anim_roll_duration " , " 3.5 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Продолжительность принудительной анимации 'idleonfire' (сек) " )
local cv_anim_roll_impact_threshold = CreateConVar ( " fedhoria_falling_anim_roll_impact_threshold " , " 300 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Мин. скорость удара для запуска анимации " )
local cv_anim_roll_playback_rate = CreateConVar ( " fedhoria_falling_anim_roll_playback_rate " , " 3.0 " , { FCVAR_ARCHIVE , FCVAR_REPLICATED } , " Скорость воспроизведения анимации 'idleonfire' " )
2026-05-25 05:07:46 +00:00
-- Death timer
2026-05-25 04:57:41 +00:00
local die_time = CreateConVar ( " fedhoria_dietime " , 5 , { FCVAR_ARCHIVE , FCVAR_REPLICATED } )
local die_time_variation = CreateConVar ( " fedhoria_dietime_variation " , 3 , { FCVAR_ARCHIVE , FCVAR_REPLICATED } )
2026-05-25 05:07:46 +00:00
-- Do it!
2026-05-25 04:57:41 +00:00
function MODULE : DoTwitch ( )
if not IsValid ( self ) or not IsValid ( self : GetTarget ( ) ) then return end
if not cv_twitch_enabled : GetBool ( ) then return end
local phys = self : GetPhysicsObject ( )
if not IsValid ( phys ) then return end
local bone_count = phys : GetBoneCount ( )
if bone_count <= 1 then return end -- нет костей для дергания (кроме, возможно, корневой)
local phys_bone = nil
local attempts = 0
local bone_index = - 1 -- есл нету кости то иди нахуй
-- нахуй игнорируем кости, которые не нужны для дергания
repeat
bone_index = math_random ( 0 , bone_count - 1 )
if not table_HasValue ( ignore_bone_indices_twitch , bone_index ) then
phys_bone = phys : GetBone ( bone_index )
end
attempts = attempts + 1
until IsValid ( phys_bone ) or attempts > 20 -- мало попытов но если не нашли то идем нахуй
if IsValid ( phys_bone ) then
local force = math_Rand ( cv_twitch_force_min : GetFloat ( ) , cv_twitch_force_max : GetFloat ( ) )
local torque = VectorRand ( ) : GetNormal ( ) * force -- сила есть ума не надо
phys_bone : AddAngleVelocity ( torque )
-- print("[Fedhoria Twitch] Applied torque", torque, "to bone", bone_index)
-- else
-- print("[Fedhoria Twitch] Could not find a valid bone to twitch after", attempts, "attempts.")
end
-- следующее дергание
self : ScheduleNextTwitch ( )
end
-- следующая дрочка
function MODULE : ScheduleNextTwitch ( )
if not IsValid ( self ) then return end
if not cv_twitch_enabled : GetBool ( ) then return end
local timer_name = " Fedhoria_FallingTorso_Twitch_ " .. self : EntIndex ( )
timer.Remove ( timer_name ) -- пашол нахуй этот таймер
local delay = math_Rand ( cv_twitch_interval_min : GetFloat ( ) , cv_twitch_interval_max : GetFloat ( ) )
timer.Create ( timer_name , delay , 1 , function ( )
if not IsValid ( self ) then return end
self : DoTwitch ( )
end )
-- print("[Fedhoria Twitch] Scheduled next twitch in", delay, "seconds.") -- ебаная отладка
end
function MODULE : StartAnimationRoll ( )
if not cv_anim_roll_enabled : GetBool ( ) then return end
local target = self : GetTarget ( )
if not IsValid ( target ) then return end
local cur_time = CurTime ( )
self.AnimationRollEndTime = cur_time + cv_anim_roll_duration : GetFloat ( )
-- нужная анимация бля
local seq = self : LookupSequence ( " idleonfire " )
if seq then
self : ResetSequence ( seq )
self : SetPlaybackRate ( cv_anim_roll_playback_rate : GetFloat ( ) )
else
print ( " [Fedhoria AnimRoll ERROR] Sequence 'idleonfire' not found! " )
self.AnimationRollEndTime = 0
return
end
self.StartDie = nil -- блять я заебался с этой хуйней
-- print("[Fedhoria AnimRoll] StartAnimationRoll initiated. Speed:", cv_anim_roll_playback_rate:GetFloat(), "Duration:", cv_anim_roll_duration:GetFloat(), "End Time:", self.AnimationRollEndTime) -- Debug
end
function MODULE : Init ( )
local seq = self : LookupSequence ( " idleonfire " )
if seq then self : ResetSequence ( seq ) end
self : SetPlaybackRate ( 1 )
self.LastCollideTime = 0
self.LastGroundCollideTime = 0
self.StartDie = nil
self.AnimationRollEndTime = 0
-- идте нахуй с этой хуйней
self : ScheduleNextTwitch ( )
end
function MODULE : Think ( )
end
function MODULE : PhysicsCollide ( ent , data )
if data.HitEntity == self then return end
-- if data.HitEntity == self:GetTarget() then return end
local cur_time = CurTime ( )
self.LastCollideTime = cur_time
-- пизда, если это не земля
if ( data.HitNormal . z > 0.7 ) then
local impact_speed = data.Speed
-- print("[Fedhoria Collide] Ground impact detected. Speed:", impact_speed, "Threshold:", cv_anim_roll_impact_threshold:GetFloat()) -- Debug
-- перекат ебаный
if cv_anim_roll_enabled : GetBool ( ) and
impact_speed > cv_anim_roll_impact_threshold : GetFloat ( ) and
cur_time > self.AnimationRollEndTime and -- анимация пошла нахуй если не запускаеться
cur_time > self.LastGroundCollideTime + cv_anim_roll_min_delay : GetFloat ( ) then -- минимальная задержка перед идте нахуй
-- print("[Fedhoria AnimRoll] Ground Impact Threshold met. Speed:", impact_speed) -- Debug
self : StartAnimationRoll ( )
end
self.LastGroundCollideTime = cur_time
-- else -- Debug для других столкновений
-- print("[Fedhoria Collide] Non-ground collision. Normal Z:", data.HitNormal.z)
end
end
function MODULE : PhysicsSimulate ( phys , dt )
local cur_time = CurTime ( )
local target = self : GetTarget ( )
if not IsValid ( target ) then self : Remove ( ) ; return false end -- если цели нет, то идем нахуй
-- проверка на физику
if cur_time < self.AnimationRollEndTime then
-- print("[Fedhoria Sim] In Animation Roll. Time left:", self.AnimationRollEndTime - cur_time) -- Debug
-- self.StartDie = nil -- Сбрасываем таймер смерти
return true -- стандартная физика пошла нахуй, у меня по ней 2
-- return false -- если физика нахуй идет
end
-- --- логика идет нахуй
-- логика для таймера
local f = 1 -- сила есть ума не надо (по умолчанию 1)
if self.StartDie then
f = math_Clamp ( 1 - ( cur_time - self.StartDie ) / die_time : GetFloat ( ) , 0 , 1 )
end
print ( f )
-- ебаная логика для regmod
if ragmod and ragmod : IsRagmodRagdoll ( target ) then
local owner = target : GetOwningPlayer ( )
-- владелец идот нахуй
f = ( IsValid ( owner ) and owner : Alive ( ) ) and 1 or 0
self.StartDie = nil
if f <= 0 then self.AnimationRollEndTime = 0 end
end
--
if ( f <= 0 ) then
-- print("[Fedhoria Sim] Removing entity (f <= 0)") -- Debug
self : Remove ( )
return false -- Прекращаем хуйню
end
local phys_bone_id = phys : GetID ( ) -- айди кости
-- ыыыуыыыыыыыы
if ( phys_bone_id == 0 ) then
-- логика для блядской воды (если торс попал в воду)
if target : WaterLevel ( ) > 0 then
-- print("[Fedhoria Sim] Target in water.") -- Debug
self.AnimationRollEndTime = 0 -- нахуй анимация пошла
local seq_choked = self : LookupSequence ( " Choked_Barnacle " )
if seq_choked then self : ResetSequence ( seq_choked ) end
-- возможн нужно добавить таймер на удаление или другую логику для воды
-- timer.Simple(0.5, function() if IsValid(self) then self:Remove() end end) -- пример опиздюливания через 5 сек
return false
end
-- логика для анимации переката
local vel = phys : GetVelocity ( )
local pbr = math_Clamp ( vel.z / - 600 , 0.5 , 1.5 )
-- падения и ебаная скорость
-- если мы не в.. а впрочем иди нахуй
if self : GetSequence ( ) ~= self : LookupSequence ( " idleonfire " ) or self : GetPlaybackRate ( ) ~= pbr then
local seq_idle = self : LookupSequence ( " idleonfire " )
if seq_idle then
-- print("[Fedhoria Sim] Resetting sequence to idleonfire, pbr:", pbr) -- Debug
self : ResetSequence ( seq_idle )
self : SetPlaybackRate ( pbr )
end
end
-- логика таймера ебаного умирания
local pos = phys : GetPos ( )
self.last_pos = self.last_pos or pos
local offset_sqr = ( pos - self.last_pos ) : LengthSqr ( )
self.last_pos = pos
if ( offset_sqr < ( 10 * 10 * dt * dt ) and not ( ragmod and ragmod : IsRagmodRagdoll ( target ) ) ) then -- uме ньшил порог неподвижности
self.StartDie = self.StartDie or cur_time -- идите нахуй
-- print("[Fedhoria Sim] Torso seems stationary. StartDie:", self.StartDie) -- Debug
else
-- self.StartDie = nil -- нахуй таймер
-- print("[Fedhoria Sim] Torso moved. Resetting StartDie.") -- Debug
end
--
local delta_collide = cur_time - self.LastCollideTime
if ( delta_collide < 0.2 ) then
return true , 1 * f -- сила есть ума не надо
elseif ( delta_collide < 1.2 ) then
return true , ( 1 - ( delta_collide - 0.2 ) ) * f -- ебаная сила
end
return true , f
end
-- --- отстали от жизни
-- затухание
local delta_collide = cur_time - self.LastCollideTime
if ( delta_collide < 0.2 ) then
return true , 1 * f
elseif ( delta_collide < 1.2 ) then
return true , ( 1 - ( delta_collide - 0.2 ) ) * f
end
return true , f
end
function MODULE : OnRemove ( )
-- пошел нахуй таймер
local timer_name = " Fedhoria_FallingTorso_Twitch_ " .. self : EntIndex ( )
timer.Remove ( timer_name )
-- print("[Fedhoria] OnRemove called for", self:EntIndex(), "Timer removed:", timer_name) -- Debug
end