Initial commit
This commit is contained in:
30
addons/qwb/lua/autorun/qwb.lua
Normal file
30
addons/qwb/lua/autorun/qwb.lua
Normal file
@@ -0,0 +1,30 @@
|
||||
qwb = qwb or {}
|
||||
|
||||
local function includeClient(path)
|
||||
if SERVER then
|
||||
AddCSLuaFile(path)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
include(path)
|
||||
end
|
||||
end
|
||||
|
||||
local function includeServer(path)
|
||||
if SERVER then
|
||||
include(path)
|
||||
end
|
||||
end
|
||||
|
||||
local function includeShared(path)
|
||||
if SERVER then
|
||||
AddCSLuaFile(path)
|
||||
end
|
||||
|
||||
include(path)
|
||||
end
|
||||
|
||||
includeServer('qwb/sv_init.lua')
|
||||
includeShared('qwb/sh_init.lua')
|
||||
includeClient('qwb/cl_init.lua')
|
||||
includeClient('qwb/cl_spawnmenu.lua')
|
||||
18
addons/qwb/lua/entities/qwb_dummy.lua
Normal file
18
addons/qwb/lua/entities/qwb_dummy.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = 'anim'
|
||||
ENT.Base = 'base_gmodentity'
|
||||
ENT.PrintName = 'QWB Dummy'
|
||||
ENT.Author = 'qurs'
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = true
|
||||
|
||||
if SERVER then
|
||||
function ENT:Initialize()
|
||||
self:PhysicsInit(SOLID_NONE)
|
||||
self:SetMoveType(MOVETYPE_NONE)
|
||||
|
||||
self:SetLocalAngularVelocity(Angle())
|
||||
end
|
||||
end
|
||||
198
addons/qwb/lua/qwb/cl_fp.lua
Normal file
198
addons/qwb/lua/qwb/cl_fp.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
stwFP = stwFP or {}
|
||||
|
||||
local fpEnabled = false
|
||||
|
||||
local nonFPWeapons = {
|
||||
['weapon_physgun'] = true,
|
||||
['gmod_tool'] = true,
|
||||
['weapon_physcannon'] = true,
|
||||
['gmod_camera'] = true,
|
||||
}
|
||||
|
||||
function stwFP.hideHead(b)
|
||||
local ply = LocalPlayer()
|
||||
|
||||
if b then
|
||||
ply:ManipulateBoneScale(ply:LookupBone('ValveBiped.Bip01_Head1') or 0, Vector(0.01, 0.01, 0.01))
|
||||
else
|
||||
ply:ManipulateBoneScale(ply:LookupBone('ValveBiped.Bip01_Head1') or 0, Vector(1, 1, 1))
|
||||
end
|
||||
|
||||
ply.headHided = b
|
||||
end
|
||||
|
||||
function stwFP.blind(b)
|
||||
if b then
|
||||
hook.Add('RenderScreenspaceEffects', 'qwb.fp.setBlind', function()
|
||||
DrawColorModify({
|
||||
[ "$pp_colour_addr" ] = 0, -- no change
|
||||
[ "$pp_colour_addg" ] = 0, -- no change
|
||||
[ "$pp_colour_addb" ] = 0, -- no change
|
||||
[ "$pp_colour_brightness" ] = -1,
|
||||
[ "$pp_colour_contrast" ] = 1, -- no change
|
||||
[ "$pp_colour_colour" ] = 1, -- no change
|
||||
[ "$pp_colour_mulr" ] = 0, -- no change
|
||||
[ "$pp_colour_mulg" ] = 0, -- no change
|
||||
[ "$pp_colour_mulb" ] = 0, -- no change
|
||||
})
|
||||
end)
|
||||
else
|
||||
hook.Remove('RenderScreenspaceEffects', 'qwb.fp.setBlind')
|
||||
end
|
||||
end
|
||||
|
||||
function stwFP.startFP()
|
||||
fpEnabled = true
|
||||
|
||||
if not LocalPlayer().headHided then
|
||||
stwFP.hideHead(true)
|
||||
end
|
||||
|
||||
local texturesHit = false
|
||||
|
||||
hook.Add('RenderScreenspaceEffects', 'qwb.fp.effects', function()
|
||||
if not texturesHit then return end
|
||||
|
||||
DrawColorModify({
|
||||
[ "$pp_colour_addr" ] = 0, -- no change
|
||||
[ "$pp_colour_addg" ] = 0, -- no change
|
||||
[ "$pp_colour_addb" ] = 0, -- no change
|
||||
[ "$pp_colour_brightness" ] = -1,
|
||||
[ "$pp_colour_contrast" ] = 1, -- no change
|
||||
[ "$pp_colour_colour" ] = 1, -- no change
|
||||
[ "$pp_colour_mulr" ] = 0, -- no change
|
||||
[ "$pp_colour_mulg" ] = 0, -- no change
|
||||
[ "$pp_colour_mulb" ] = 0, -- no change
|
||||
})
|
||||
end)
|
||||
|
||||
hook.Add('CalcView', 'qwb.fp', function(ply, origin, ang, fov, znear, zfar)
|
||||
if not IsValid(LocalPlayer()) then return end
|
||||
if ply ~= LocalPlayer() then return end
|
||||
if not LocalPlayer():LookupBone('ValveBiped.Bip01_Head1') then return end
|
||||
|
||||
if ply:Alive() then
|
||||
local pos, angles = LocalPlayer():GetBonePosition( LocalPlayer():LookupBone('ValveBiped.Bip01_Head1') )
|
||||
|
||||
local cameraPos = pos + ang:Right() * 0
|
||||
cameraPos = cameraPos + ang:Up() * 4
|
||||
cameraPos = cameraPos + ply:GetForward() * 1
|
||||
|
||||
local filter = player.GetAll()
|
||||
filter[#filter + 1] = ply
|
||||
filter[#filter + 1] = ply:GetActiveWeapon()
|
||||
table.Add(filter, ents.FindByClass('gmod_sent_vehicle_fphysics_base'))
|
||||
|
||||
local tr = util.TraceHull({
|
||||
start = pos,
|
||||
endpos = cameraPos,
|
||||
filter = filter,
|
||||
mins = Vector(-4.5,-4.5,-4.5),
|
||||
maxs = Vector(4.5, 4.5, 4.5),
|
||||
})
|
||||
cameraPos = tr.HitPos
|
||||
|
||||
if tr.Hit and not texturesHit then
|
||||
texturesHit = true
|
||||
elseif not tr.Hit and texturesHit then
|
||||
texturesHit = false
|
||||
end
|
||||
|
||||
-- if not qwb.ironsighted and qwb.IronSightLerp then
|
||||
-- local sub = qwb.IronSightLerp - cameraPos
|
||||
-- if math.abs(sub.x) > 1.5 or math.abs(sub.y) > 1.5 or math.abs(sub.z) > 1.5 then
|
||||
-- qwb.IronSightLerp = Lerp(0.4, qwb.IronSightLerp, cameraPos)
|
||||
-- else
|
||||
-- qwb.IronSightLerp = nil
|
||||
-- end
|
||||
-- elseif qwb.ironsighted and not qwb.IronSightLerp then
|
||||
-- qwb.IronSightLerp = cameraPos
|
||||
-- end
|
||||
|
||||
return {
|
||||
-- origin = qwb.IronSightLerp or cameraPos,
|
||||
origin = cameraPos,
|
||||
angles = Angle((ang.p > 65 and 65) or (ang.p < -65 and -65) or ang.p, ang.y + math.sin(SysTime() / 1.5) * 0.5, ang.r + math.sin(SysTime()) * 0.5),
|
||||
fov = fov,
|
||||
drawviewer = true,
|
||||
}
|
||||
else
|
||||
if IsValid(ply:GetRagdollEntity()) then
|
||||
if texturesHit then texturesHit = false end
|
||||
|
||||
local ragdoll = ply:GetRagdollEntity()
|
||||
|
||||
local bone = ragdoll:LookupBone('ValveBiped.Bip01_Head1') or 0
|
||||
|
||||
if ragdoll:GetManipulateBoneScale(bone) ~= Vector(0.01, 0.01, 0.01) then
|
||||
ragdoll:ManipulateBoneScale(bone, Vector(0.01, 0.01, 0.01))
|
||||
end
|
||||
|
||||
local pos, angles = ragdoll:GetBonePosition(bone)
|
||||
|
||||
return {
|
||||
origin = pos,
|
||||
angles = angles + Angle(-90,0,-90),
|
||||
fov = fov,
|
||||
drawviewer = false,
|
||||
}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add('InputMouseApply', 'qwb.fp', function(cmd, x, y, ang)
|
||||
ang.p = math.Clamp(ang.p + y / 50, -65, 65)
|
||||
ang.y = ang.y - x / 50
|
||||
cmd:SetViewAngles(ang)
|
||||
|
||||
return true
|
||||
end)
|
||||
|
||||
hook.Add('HUDShouldDraw', 'qwb.fp.crosshair', function(name)
|
||||
if name == 'CHudCrosshair' then return false end
|
||||
end)
|
||||
end
|
||||
|
||||
function stwFP.stopFP()
|
||||
hook.Remove('CalcView', 'qwb.fp')
|
||||
hook.Remove('InputMouseApply', 'qwb.fp')
|
||||
hook.Remove('RenderScreenspaceEffects', 'qwb.fp.effects')
|
||||
|
||||
fpEnabled = false
|
||||
|
||||
if LocalPlayer().headHided then
|
||||
stwFP.hideHead(false)
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add('qwb.fp.canEnableFP', 'qwb.fp', function()
|
||||
if not IsValid(LocalPlayer()) then return end
|
||||
if not IsValid(LocalPlayer():GetActiveWeapon()) then return end
|
||||
|
||||
if GetViewEntity() ~= LocalPlayer() then return false end
|
||||
if nonFPWeapons[LocalPlayer():GetActiveWeapon():GetClass()] then return false end
|
||||
end)
|
||||
|
||||
hook.Add('Think', 'qwb.fp.waiting', function()
|
||||
if not LocalPlayer() or not IsValid(LocalPlayer()) or LocalPlayer() == NULL then return end
|
||||
|
||||
if hook.Run('qwb.fp.canEnableFP') ~= false and not fpEnabled then
|
||||
stwFP.startFP()
|
||||
elseif hook.Run('qwb.fp.canEnableFP') == false and fpEnabled then
|
||||
stwFP.stopFP()
|
||||
end
|
||||
|
||||
if LocalPlayer():Alive() and IsValid(LocalPlayer():GetRagdollEntity()) then
|
||||
local ragdoll = LocalPlayer():GetRagdollEntity()
|
||||
|
||||
if ragdoll:GetManipulateBoneScale(ragdoll:LookupBone('ValveBiped.Bip01_Head1') or 0) ~= Vector(1, 1, 1) then
|
||||
ragdoll:ManipulateBoneScale(ragdoll:LookupBone('ValveBiped.Bip01_Head1') or 0, Vector(1, 1, 1))
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
timer.Create('qwb.fp.checkHead', 3.5, 0, function()
|
||||
if LocalPlayer().headHided and LocalPlayer():GetManipulateBoneScale(LocalPlayer():LookupBone('ValveBiped.Bip01_Head1') or 0) ~= Vector(0.01, 0.01, 0.01) then
|
||||
stwFP.hideHead(true)
|
||||
end
|
||||
end)
|
||||
206
addons/qwb/lua/qwb/cl_init.lua
Normal file
206
addons/qwb/lua/qwb/cl_init.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
local firstPersonMode = CreateClientConVar('qwb_firstperson', 0, true, false, 'FirstPerson Mode (from the hip)', 0, 2)
|
||||
local firstPersonZNear = CreateClientConVar('qwb_firstperson_znear', 1.75, true, false, 'FirstPerson ZNear', 1, 5)
|
||||
|
||||
net.Receive('qwb.setIronsight', function()
|
||||
local b = net.ReadBool()
|
||||
|
||||
qwb.ironsighted = b
|
||||
end)
|
||||
|
||||
local angle_zero = Angle()
|
||||
local firstPersonOffset1 = Vector()
|
||||
local firstPersonOffset2 = Vector(-2, 0, 5)
|
||||
|
||||
local headDefaultScale = Vector(1, 1, 1)
|
||||
local headScale = Vector(0.01, 0.01, 0.01)
|
||||
|
||||
local function hideHead(ply, boneID)
|
||||
if not IsValid(ply) then return false end
|
||||
|
||||
boneID = boneID or ply:LookupBone('ValveBiped.Bip01_Head1')
|
||||
if not boneID then return end
|
||||
|
||||
local curHeadScale = ply:GetManipulateBoneScale(boneID)
|
||||
if curHeadScale ~= headScale then
|
||||
ply:ManipulateBoneScale(boneID, headScale)
|
||||
end
|
||||
end
|
||||
|
||||
local function showHead(ply, boneID)
|
||||
if not IsValid(ply) then return false end
|
||||
|
||||
boneID = boneID or ply:LookupBone('ValveBiped.Bip01_Head1')
|
||||
if not boneID then return end
|
||||
|
||||
local curHeadScale = ply:GetManipulateBoneScale(boneID)
|
||||
if curHeadScale ~= headDefaultScale then
|
||||
ply:ManipulateBoneScale(boneID, headDefaultScale)
|
||||
end
|
||||
end
|
||||
|
||||
local function shouldChangeCalcView(ply)
|
||||
if not IsValid(ply) then return false end
|
||||
if GetViewEntity() ~= LocalPlayer() then return false end
|
||||
if not ply:Alive() then return false end
|
||||
|
||||
local weap = ply:GetActiveWeapon()
|
||||
if not IsValid(weap) or not weap.IsQWB then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local firstPersonModes = {
|
||||
[0] = function(ply, origin, angles)
|
||||
local att = ply:GetAttachment( ply:LookupAttachment('eyes') )
|
||||
if not att then return end
|
||||
|
||||
local pos, ang = LocalToWorld(firstPersonOffset1, angle_zero, att.Pos, att.Ang)
|
||||
return pos, ang
|
||||
end,
|
||||
|
||||
[1] = function(ply, origin, angles)
|
||||
local att = ply:GetAttachment( ply:LookupAttachment('anim_attachment_head') )
|
||||
if not att then return end
|
||||
|
||||
local pos, ang = LocalToWorld(firstPersonOffset2, angle_zero, att.Pos, angles)
|
||||
return pos, ang
|
||||
end,
|
||||
}
|
||||
|
||||
local function getSightPos(ply)
|
||||
local weap = ply:GetActiveWeapon()
|
||||
local att = ply:GetAttachment( ply:LookupAttachment('anim_attachment_rh') )
|
||||
if not att then return end
|
||||
|
||||
local offset = weap.IronsightOffset
|
||||
local angOffset = weap.IronsightAngle
|
||||
|
||||
if weap.Attachments and weap._attachments and weap._attachments.sights then
|
||||
local id = weap._attachments.sights.id
|
||||
local data = weap.Attachments.sights[id]
|
||||
if data then
|
||||
local camOffset = data.sightCameraOffset
|
||||
if camOffset then
|
||||
offset = offset + camOffset
|
||||
end
|
||||
|
||||
local camAngOffset = data.sightCameraAngleOffset
|
||||
if camAngOffset then
|
||||
angOffset = angOffset + camAngOffset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return LocalToWorld(offset, angOffset or angle_zero, att.Pos, att.Ang)
|
||||
end
|
||||
|
||||
local function nonSightCalcView(ply, origin, angles, fov, znear, zfar)
|
||||
if not shouldChangeCalcView(ply) then
|
||||
qwb.ironsightLerpProgress = nil
|
||||
return
|
||||
end
|
||||
|
||||
qwb.ironsightLerpProgress = qwb.ironsightLerpProgress or 0
|
||||
qwb.ironsightLerpProgress = math.Clamp(qwb.ironsightLerpProgress - (FrameTime() * 4), 0, 1)
|
||||
|
||||
local mode = firstPersonMode:GetInt()
|
||||
|
||||
local getPosFunc = firstPersonModes[mode]
|
||||
if not getPosFunc then return end
|
||||
|
||||
local pos, ang = getPosFunc(ply, origin, angles)
|
||||
if not pos then return end
|
||||
|
||||
local sightPos = getSightPos(ply) or origin
|
||||
pos = LerpVector(qwb.ironsightLerpProgress, pos, sightPos)
|
||||
|
||||
return {
|
||||
origin = pos,
|
||||
angles = ang,
|
||||
fov = fov,
|
||||
drawviewer = true,
|
||||
znear = firstPersonZNear:GetFloat() or 1.75,
|
||||
}
|
||||
end
|
||||
|
||||
timer.Create('qwb.headCheck', 0.5, 0, function()
|
||||
if not shouldChangeCalcView(LocalPlayer()) or (firstPersonMode:GetInt() ~= 1 and not qwb.ironsighted) then
|
||||
showHead(LocalPlayer())
|
||||
elseif shouldChangeCalcView(LocalPlayer()) and (firstPersonMode:GetInt() == 1 or qwb.ironsighted) then
|
||||
hideHead(LocalPlayer())
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add('InputMouseApply', 'qwb.firstPerson', function(cmd, x, y, ang)
|
||||
local mode = firstPersonMode:GetInt()
|
||||
if mode ~= 1 then return end
|
||||
|
||||
if not shouldChangeCalcView(LocalPlayer()) then return end
|
||||
|
||||
ang.p = math.Clamp(ang.p + y / 50, -65, 65)
|
||||
ang.y = ang.y - x / 50
|
||||
cmd:SetViewAngles(ang)
|
||||
|
||||
return true
|
||||
end)
|
||||
|
||||
hook.Add('CalcView', 'qwb.ironsight', function(ply, origin, angles, fov, znear, zfar)
|
||||
if not qwb.ironsighted then return nonSightCalcView(ply, origin, angles, fov, znear, zfar) end
|
||||
|
||||
if not shouldChangeCalcView(ply) or qwb.isPlayerRunning(ply) then
|
||||
qwb.ironsighted = nil
|
||||
qwb.ironsightLerpProgress = nil
|
||||
return
|
||||
end
|
||||
|
||||
local pos, ang = getSightPos(ply)
|
||||
|
||||
qwb.ironsightLerpProgress = qwb.ironsightLerpProgress or 0
|
||||
qwb.ironsightLerpProgress = math.Clamp(qwb.ironsightLerpProgress + (FrameTime() * 3), 0, 1)
|
||||
|
||||
local mode = firstPersonMode:GetInt()
|
||||
local getFunc = firstPersonModes[mode]
|
||||
local nonSightPos = getFunc and getFunc(ply, origin, angles) or origin
|
||||
|
||||
pos = LerpVector(qwb.ironsightLerpProgress, nonSightPos, pos)
|
||||
|
||||
local weap = ply:GetActiveWeapon()
|
||||
|
||||
local view = {
|
||||
origin = pos,
|
||||
angles = ang,
|
||||
fov = fov,
|
||||
znear = weap.IronsightZNear or 2.35,
|
||||
drawviewer = true,
|
||||
}
|
||||
|
||||
return view
|
||||
end)
|
||||
|
||||
-- Thanks to octothorp team for this solution, which fixes camera shake
|
||||
hook.Add('RenderScene', '_qwb', function(pos, angle, fov)
|
||||
local camData = hook.Run('CalcView', LocalPlayer(), pos, angle, fov)
|
||||
if not camData then return end
|
||||
|
||||
render.Clear(0, 0, 0, 255, true, true, true)
|
||||
render.RenderView({
|
||||
angles = camData.angles,
|
||||
origin = camData.origin,
|
||||
drawhud = true,
|
||||
drawmonitors = true,
|
||||
dopostprocess = true,
|
||||
})
|
||||
|
||||
return true
|
||||
end)
|
||||
|
||||
function qwb.fullyClearStencil()
|
||||
render.SetStencilWriteMask( 0xFF )
|
||||
render.SetStencilTestMask( 0xFF )
|
||||
render.SetStencilReferenceValue( 0 )
|
||||
render.SetStencilCompareFunction( STENCIL_ALWAYS )
|
||||
render.SetStencilPassOperation( STENCIL_KEEP )
|
||||
render.SetStencilFailOperation( STENCIL_KEEP )
|
||||
render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||
render.ClearStencil()
|
||||
end
|
||||
37
addons/qwb/lua/qwb/cl_spawnmenu.lua
Normal file
37
addons/qwb/lua/qwb/cl_spawnmenu.lua
Normal file
@@ -0,0 +1,37 @@
|
||||
local lang = GetConVar('gmod_language'):GetString()
|
||||
|
||||
language.Add('qwb.tab', 'QWB')
|
||||
|
||||
if lang == 'ru' then
|
||||
language.Add('qwb.options', 'Настройки')
|
||||
language.Add('qwb.clientSettings', 'Клиентские настройки')
|
||||
language.Add('qwb.serverSettings', 'Серверные настройки')
|
||||
language.Add('qwb.firstPersonSelector.slider', 'Режим первого лица (от бедра)')
|
||||
language.Add('qwb.firstPersonZNear.slider', 'Ограничение рендера от первого лица (ZNear)')
|
||||
language.Add('qwb.realisticDamage.checkbox', 'Включить реалистичный урон')
|
||||
language.Add('qwb.realisticDamage.checkbox.tooltip', 'Урон будет масштабироваться в зависимости от части тела, куда попадает пуля')
|
||||
elseif lang == 'en' then
|
||||
language.Add('qwb.options', 'Options')
|
||||
language.Add('qwb.clientSettings', 'Client Settings')
|
||||
language.Add('qwb.serverSettings', 'Server Settings')
|
||||
language.Add('qwb.firstPersonSelector.slider', 'First person mode (from the hip)')
|
||||
language.Add('qwb.firstPersonZNear.slider', 'Clipping a first person render (ZNear)')
|
||||
language.Add('qwb.realisticDamage.checkbox', 'Enable realistic damage')
|
||||
language.Add('qwb.realisticDamage.checkbox.tooltip', 'Damage will scale based on the part of the body the bullet hits')
|
||||
end
|
||||
|
||||
hook.Add('AddToolMenuTabs', 'qwb', function()
|
||||
spawnmenu.AddToolTab('qwb', '#qwb.tab', 'icon16/user_edit.png')
|
||||
spawnmenu.AddToolCategory('qwb', 'qwb.options', '#qwb.options')
|
||||
|
||||
spawnmenu.AddToolMenuOption('qwb', 'qwb.options', 'qwb.clientSettings', '#qwb.clientSettings', '', '', function(pnl)
|
||||
pnl:ClearControls()
|
||||
pnl:NumSlider('#qwb.firstPersonSelector.slider', 'qwb_firstperson', 0, 2, 0):SetTooltip('#qwb.firstPersonSelector.slider')
|
||||
pnl:NumSlider('#qwb.firstPersonZNear.slider', 'qwb_firstperson_znear', 1, 5, 2):SetTooltip('#qwb.firstPersonZNear.slider')
|
||||
end)
|
||||
|
||||
spawnmenu.AddToolMenuOption('qwb', 'qwb.options', 'qwb.serverSettings', '#qwb.serverSettings', '', '', function(pnl)
|
||||
pnl:ClearControls()
|
||||
pnl:CheckBox('#qwb.realisticDamage.checkbox', 'qwb_realisticdamage'):SetTooltip('#qwb.realisticDamage.checkbox.tooltip')
|
||||
end)
|
||||
end)
|
||||
5
addons/qwb/lua/qwb/sh_init.lua
Normal file
5
addons/qwb/lua/qwb/sh_init.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
function qwb.isPlayerRunning(ply)
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
return ply:KeyDown(IN_SPEED) and ply:GetVelocity():LengthSqr() > 0
|
||||
end
|
||||
28
addons/qwb/lua/qwb/sv_init.lua
Normal file
28
addons/qwb/lua/qwb/sv_init.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
util.AddNetworkString('qwb.setIronsight')
|
||||
util.AddNetworkString('qwb.setAttachment')
|
||||
util.AddNetworkString('qwb.removeAttachment')
|
||||
util.AddNetworkString('qwb.muzzleFlashLight')
|
||||
|
||||
local realisticDamage = CreateConVar('qwb_realisticdamage', 1, FCVAR_NOTIFY, '', 0, 1)
|
||||
|
||||
local hitgroups = {
|
||||
[HITGROUP_HEAD] = 10000,
|
||||
[HITGROUP_STOMACH] = 1.5,
|
||||
[HITGROUP_LEFTARM] = 0.2,
|
||||
[HITGROUP_RIGHTARM] = 0.2,
|
||||
[HITGROUP_LEFTLEG] = 0.3,
|
||||
[HITGROUP_RIGHTLEG] = 0.3,
|
||||
}
|
||||
|
||||
hook.Add('ScalePlayerDamage', 'qwb.damage', function( ply, hitgroup, dmginfo )
|
||||
if not realisticDamage:GetBool() then return end
|
||||
|
||||
local attacker = dmginfo:GetAttacker()
|
||||
if not IsValid(attacker) or not IsValid(attacker:GetActiveWeapon()) then return end
|
||||
|
||||
local weap = attacker:GetActiveWeapon()
|
||||
if not weap.IsQWB then return end
|
||||
|
||||
local scale = hitgroups[hitgroup]
|
||||
if scale then dmginfo:ScaleDamage(scale) end
|
||||
end)
|
||||
43
addons/qwb/lua/weapons/qwb_awp.lua
Normal file
43
addons/qwb/lua/weapons/qwb_awp.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Base = 'weapon_base_qwb'
|
||||
|
||||
SWEP.WorldModel = 'models/weapons/w_snip_awp.mdl'
|
||||
|
||||
SWEP.PrintName = 'AWP'
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.IronsightOffset = Vector(-3.1, -0.8, 6.7)
|
||||
SWEP.IronsightAngle = Angle(-5, -2, 0)
|
||||
|
||||
SWEP.Primary.Sound = 'Weapon_AWP.Single'
|
||||
SWEP.Primary.Damage = 85
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Spread = 0.005
|
||||
SWEP.Primary.Delay = 1
|
||||
|
||||
SWEP.Primary.ClipSize = 8
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = '357'
|
||||
|
||||
SWEP.Recoil = 8
|
||||
SWEP.HorizontalRecoil = 8
|
||||
|
||||
SWEP.HipFireRecoil = 5
|
||||
|
||||
SWEP.HoldType = 'ar2'
|
||||
|
||||
SWEP.ScopeOffset = Vector(-36.9, 3.47, -0.955)
|
||||
SWEP.ScopeSize = {184, 186}
|
||||
SWEP.ScopeMat = Material('materials/qwb/scope/awp.png')
|
||||
SWEP.ScopeFOV = 10
|
||||
|
||||
SWEP.ShellType = '762Nato'
|
||||
SWEP.ShellOffset = Vector(-33, 1, -0.5)
|
||||
SWEP.ShellVelocity = 75
|
||||
|
||||
SWEP.AimSound = Sound('weapons/ammopickup.wav')
|
||||
36
addons/qwb/lua/weapons/qwb_glock18.lua
Normal file
36
addons/qwb/lua/weapons/qwb_glock18.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Base = 'weapon_base_qwb'
|
||||
|
||||
SWEP.WorldModel = 'models/weapons/w_pist_glock18.mdl'
|
||||
|
||||
SWEP.PrintName = 'Glock-18'
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.IronsightOffset = Vector(-10, -1.2, 3.95)
|
||||
SWEP.IronsightAngle = Angle(0, 2, 0)
|
||||
|
||||
SWEP.Primary.Sound = 'Weapon_Glock.Single'
|
||||
SWEP.Primary.Damage = 20
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Spread = 0.01
|
||||
SWEP.Primary.Delay = 0.12
|
||||
|
||||
SWEP.Primary.ClipSize = 12
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = 'Pistol'
|
||||
|
||||
SWEP.Recoil = 5.5
|
||||
SWEP.HorizontalRecoil = 10
|
||||
|
||||
SWEP.HoldType = 'revolver'
|
||||
|
||||
SWEP.ShellType = '9mm'
|
||||
SWEP.ShellOffset = Vector(-5, 1, -0.5)
|
||||
SWEP.ShellVelocity = -50
|
||||
|
||||
SWEP.AimSound = Sound('weapons/ammopickup.wav')
|
||||
41
addons/qwb/lua/weapons/qwb_m3super.lua
Normal file
41
addons/qwb/lua/weapons/qwb_m3super.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Base = 'weapon_base_qwb'
|
||||
|
||||
SWEP.WorldModel = 'models/weapons/w_shot_m3super90.mdl'
|
||||
|
||||
SWEP.PrintName = 'M3 Super'
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.IronsightOffset = Vector(-2.5, -0.95, 4.7)
|
||||
SWEP.IronsightAngle = Angle(-5, -2, 0)
|
||||
SWEP.IronsightZNear = 1
|
||||
|
||||
SWEP.Primary.Sound = 'Weapon_M3.Single'
|
||||
SWEP.Primary.Damage = 6
|
||||
SWEP.Primary.NumShots = 8
|
||||
SWEP.Primary.Spread = 0.1
|
||||
SWEP.Primary.Delay = 1
|
||||
|
||||
SWEP.Primary.ClipSize = 6
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = 'Buckshot'
|
||||
|
||||
SWEP.Recoil = 15
|
||||
SWEP.HorizontalRecoil = 25
|
||||
|
||||
SWEP.HipFireRecoil = 10
|
||||
|
||||
SWEP.HoldType = 'ar2'
|
||||
|
||||
SWEP.ShellType = '12Gauge'
|
||||
SWEP.ShellOffset = Vector(-20, 1, -1.5)
|
||||
SWEP.ShellVelocity = 100
|
||||
|
||||
SWEP.AimSound = Sound('weapons/ammopickup.wav')
|
||||
|
||||
SWEP.ShootPos = Vector(20, -0.8, 7.3)
|
||||
69
addons/qwb/lua/weapons/qwb_ump45.lua
Normal file
69
addons/qwb/lua/weapons/qwb_ump45.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Base = 'weapon_base_qwb'
|
||||
|
||||
SWEP.WorldModel = 'models/weapons/w_smg_ump45.mdl'
|
||||
|
||||
SWEP.PrintName = 'UMP-45'
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.IronsightOffset = Vector(-6, -0.88, 5.7)
|
||||
SWEP.IronsightAngle = Angle(0, -2, 0)
|
||||
SWEP.IronsightZNear = 0.4
|
||||
|
||||
SWEP.Primary.Sound = 'Weapon_UMP45.Single'
|
||||
SWEP.Primary.Damage = 5
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Spread = 0.01
|
||||
SWEP.Primary.Delay = 0.1
|
||||
|
||||
SWEP.Primary.ClipSize = 30
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = 'SMG1'
|
||||
|
||||
SWEP.Recoil = 2
|
||||
SWEP.HorizontalRecoil = 6.5
|
||||
|
||||
SWEP.HoldType = 'smg'
|
||||
|
||||
SWEP.ShellType = '57'
|
||||
SWEP.ShellOffset = Vector(-5, 1, 1.5)
|
||||
SWEP.ShellVelocity = 65
|
||||
|
||||
SWEP.AimSound = Sound('weapons/ammopickup.wav')
|
||||
|
||||
-- Attachments
|
||||
SWEP.Attachments = {
|
||||
sights = {
|
||||
holo_sight = {
|
||||
name = 'Holo sight',
|
||||
mdl = 'models/attachment/crysis_holo.mdl',
|
||||
pos = Vector(-3, 1.3, 6.95),
|
||||
ang = Angle(-10, 0, 0),
|
||||
scale = 1,
|
||||
|
||||
sightCameraOffset = Vector(0, 0, 0.5),
|
||||
sightCameraAngleOffset = Angle(),
|
||||
},
|
||||
|
||||
optical_sight = {
|
||||
name = 'Optical sight',
|
||||
mdl = 'models/attachment/crysis_holo.mdl',
|
||||
pos = Vector(-3, 1.3, 6.95),
|
||||
ang = Angle(-10, 0, 0),
|
||||
scale = 1,
|
||||
|
||||
sightCameraOffset = Vector(0, 0, 0.5),
|
||||
sightCameraAngleOffset = Angle(),
|
||||
|
||||
opticPos = Vector(3.5, -0.3, 1.75), -- the position of the rendered crosshair relative to the attachment model
|
||||
opticAng = Angle(-90, 0, 0),
|
||||
opticSize = {80, 80},
|
||||
opticFOV = 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
36
addons/qwb/lua/weapons/qwb_usp.lua
Normal file
36
addons/qwb/lua/weapons/qwb_usp.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.Base = 'weapon_base_qwb'
|
||||
|
||||
SWEP.WorldModel = 'models/weapons/w_pist_usp.mdl'
|
||||
|
||||
SWEP.PrintName = 'USP'
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.IronsightOffset = Vector(-10, -1.1, 4)
|
||||
SWEP.IronsightAngle = Angle(0, 3, 0)
|
||||
|
||||
SWEP.Primary.Sound = 'Weapon_USP.Single'
|
||||
SWEP.Primary.Damage = 15
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Spread = 0.01
|
||||
SWEP.Primary.Delay = 0.15
|
||||
|
||||
SWEP.Primary.ClipSize = 15
|
||||
SWEP.Primary.DefaultClip = 0
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = 'Pistol'
|
||||
|
||||
SWEP.Recoil = 5
|
||||
SWEP.HorizontalRecoil = 8
|
||||
|
||||
SWEP.HoldType = 'revolver'
|
||||
|
||||
SWEP.ShellType = '9mm'
|
||||
SWEP.ShellOffset = Vector(-4.5, 1, -1)
|
||||
SWEP.ShellVelocity = 60
|
||||
|
||||
SWEP.AimSound = Sound('weapons/ammopickup.wav')
|
||||
114
addons/qwb/lua/weapons/weapon_base_qwb/cl_att.lua
Normal file
114
addons/qwb/lua/weapons/weapon_base_qwb/cl_att.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
function SWEP:OnRemove()
|
||||
for k, v in pairs(self._attachments or {}) do
|
||||
if IsValid(v.csEnt) then v.csEnt:Remove() end
|
||||
end
|
||||
end
|
||||
|
||||
local function drawOpticAttach(self, flags)
|
||||
local weap = self.parent
|
||||
if not IsValid(weap) then return end
|
||||
|
||||
local ply = self:GetParent()
|
||||
if not IsValid(ply) then return end
|
||||
|
||||
if ply:GetActiveWeapon() ~= weap then return end
|
||||
|
||||
self:DrawModel(flags)
|
||||
|
||||
if not qwb.ironsighted then return end
|
||||
|
||||
local scopeMat = self.opticMat
|
||||
|
||||
local attID = weap:LookupAttachment('muzzle')
|
||||
if not attID then return end
|
||||
|
||||
local att = weap:GetAttachment(attID)
|
||||
if not att then return end
|
||||
|
||||
local pos, ang = LocalToWorld(self.opticPos, self.opticAng or angle2, self:GetPos(), att.Ang)
|
||||
|
||||
local w, h = unpack(self.opticSize)
|
||||
local radius = math.max(w, h)
|
||||
local semiRadius = radius * 0.5
|
||||
|
||||
qwb.fullyClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilFailOperation(STENCIL_ZERO)
|
||||
render.SetStencilZFailOperation(STENCIL_ZERO)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilReferenceValue(1)
|
||||
|
||||
cam.Start3D2D(pos, ang, 0.01)
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor(color_black)
|
||||
draw_Circle(semiRadius, semiRadius, semiRadius, 30)
|
||||
cam.End3D2D()
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
cam.Start3D2D(pos, ang, 0.01)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(mat)
|
||||
surface.DrawTexturedRect(0, 0, w, h)
|
||||
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(scopeMat)
|
||||
surface.DrawTexturedRect(0, 0, w, h)
|
||||
cam.End3D2D()
|
||||
render.SetStencilEnable(false)
|
||||
end
|
||||
|
||||
net.Receive('qwb.setAttachment', function()
|
||||
local weap = net.ReadEntity()
|
||||
if not IsValid(weap) then return end
|
||||
|
||||
local attachType, attachID = net.ReadString(), net.ReadString()
|
||||
|
||||
local data = weap.Attachments[attachType] and weap.Attachments[attachType][attachID]
|
||||
if not data then return end
|
||||
|
||||
weap._attachments = weap._attachments or {}
|
||||
weap._attachments[attachType] = weap._attachments[attachType] or {}
|
||||
|
||||
local tbl = weap._attachments[attachType]
|
||||
tbl.id = attachID
|
||||
|
||||
if IsValid(tbl.csEnt) then tbl.csEnt:Remove() end
|
||||
|
||||
local owner = weap:GetOwner()
|
||||
|
||||
if not IsValid(tbl.csEnt) then
|
||||
tbl.csEnt = ClientsideModel(data.mdl)
|
||||
tbl.csEnt:SetParent(LocalPlayer(), LocalPlayer():LookupAttachment('anim_attachment_rh'))
|
||||
tbl.csEnt:SetLocalPos(data.pos)
|
||||
tbl.csEnt:SetLocalAngles(data.ang)
|
||||
tbl.csEnt:SetModelScale(data.scale or 1)
|
||||
|
||||
tbl.csEnt.parent = weap
|
||||
|
||||
if data.opticPos and owner == LocalPlayer() then
|
||||
tbl.csEnt.opticPos = data.opticPos
|
||||
tbl.csEnt.opticAng = data.opticAng
|
||||
tbl.csEnt.opticSize = data.opticSize
|
||||
tbl.csEnt.opticMat = data.opticMat or weap.DefaultScopeMat
|
||||
|
||||
tbl.csEnt.RenderOverride = drawOpticAttach
|
||||
end
|
||||
|
||||
tbl.csEnt:Spawn()
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive('qwb.removeAttachment', function()
|
||||
local weap = net.ReadEntity()
|
||||
if not IsValid(weap) then return end
|
||||
if not weap._attachments then return end
|
||||
|
||||
local attachType = net.ReadString()
|
||||
if not weap._attachments[attachType] then return end
|
||||
|
||||
if IsValid(weap._attachments[attachType].csEnt) then weap._attachments[attachType].csEnt:Remove() end
|
||||
|
||||
weap._attachments[attachType] = nil
|
||||
end)
|
||||
38
addons/qwb/lua/weapons/weapon_base_qwb/cl_att_menu.lua
Normal file
38
addons/qwb/lua/weapons/weapon_base_qwb/cl_att_menu.lua
Normal file
@@ -0,0 +1,38 @@
|
||||
local color_bg = Color(0, 0, 0, 190)
|
||||
|
||||
function SWEP:OpenAttMenu()
|
||||
self._attMenu = vgui.Create('DPanel')
|
||||
local pnl = self._attMenu
|
||||
|
||||
pnl:SetSize(ScrW(), ScrH())
|
||||
|
||||
function pnl:Paint(w, h)
|
||||
surface.SetDrawColor(color_bg)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
end
|
||||
|
||||
qwb.attMenuOpened = true
|
||||
end
|
||||
|
||||
function SWEP:CloseAttMenu()
|
||||
self._attMenu:Remove()
|
||||
self._attMenu = nil
|
||||
|
||||
qwb.attMenuOpened = nil
|
||||
end
|
||||
|
||||
function SWEP:ToggleAttMenu()
|
||||
if IsValid(self._attMenu) then
|
||||
self:CloseAttMenu()
|
||||
else
|
||||
self:OpenAttMenu()
|
||||
end
|
||||
end
|
||||
|
||||
-- hook.Add('OnContextMenuOpen', 'qwb.att.menu', function()
|
||||
-- local weap = LocalPlayer():GetActiveWeapon()
|
||||
-- if not IsValid(weap) then return end
|
||||
-- if not weap.IsQWB then return end
|
||||
|
||||
-- weap:ToggleAttMenu()
|
||||
-- end)
|
||||
128
addons/qwb/lua/weapons/weapon_base_qwb/cl_init.lua
Normal file
128
addons/qwb/lua/weapons/weapon_base_qwb/cl_init.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
include('shared.lua')
|
||||
|
||||
include('sh_att.lua')
|
||||
include('cl_att.lua')
|
||||
include('cl_att_menu.lua')
|
||||
|
||||
local size = 512
|
||||
local RT = GetRenderTarget('qwb_scope', size, size)
|
||||
|
||||
local mat = CreateMaterial('qwb_scope', 'UnlitGeneric', {
|
||||
['$basetexture'] = RT:GetName(),
|
||||
['$translucent'] = 1,
|
||||
['$vertexcolor'] = 1,
|
||||
})
|
||||
|
||||
local vector_origin = Vector()
|
||||
local angle1, angle2 = Angle(0, 0, -90), Angle(-90, 0, 0)
|
||||
local color_white, color_black = Color(255, 255, 255), Color(0, 0, 0)
|
||||
|
||||
local function draw_Circle( x, y, radius, seg )
|
||||
local cir = {}
|
||||
|
||||
table.insert( cir, { x = x, y = y, u = 0.5, v = 0.5 } )
|
||||
for i = 0, seg do
|
||||
local a = math.rad( ( i / seg ) * -360 )
|
||||
table.insert( cir, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / 2 + 0.5, v = math.cos( a ) / 2 + 0.5 } )
|
||||
end
|
||||
|
||||
local a = math.rad( 0 ) -- This is needed for non absolute segment counts
|
||||
table.insert( cir, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / 2 + 0.5, v = math.cos( a ) / 2 + 0.5 } )
|
||||
|
||||
surface.DrawPoly( cir )
|
||||
end
|
||||
|
||||
hook.Add('Think', 'qwb.renderScope', function()
|
||||
if not qwb.ironsighted then return end
|
||||
|
||||
local weap = LocalPlayer():GetActiveWeapon()
|
||||
if not IsValid(weap) or not weap.IsQWB then return end
|
||||
|
||||
local sightData = weap:GetAttach('sights')
|
||||
if not weap.ScopeOffset and (not sightData or not IsValid(sightData.csEnt) or not sightData.csEnt.opticPos) then return end
|
||||
|
||||
local att = weap:GetAttachment( weap:LookupAttachment('muzzle') )
|
||||
if not att then return end
|
||||
local pos, ang = att.Pos, att.Ang
|
||||
|
||||
local _, scopeAng = LocalToWorld( vector_origin, angle1, pos, ang )
|
||||
|
||||
local data = sightData and weap.Attachments and weap.Attachments.sights and weap.Attachments.sights[ sightData.id ]
|
||||
|
||||
render.PushRenderTarget(RT)
|
||||
render.RenderView({
|
||||
origin = pos,
|
||||
angles = scopeAng,
|
||||
fov = weap.ScopeFOV or (data and data.opticFOV) or 10,
|
||||
})
|
||||
render.PopRenderTarget()
|
||||
end)
|
||||
|
||||
net.Receive('qwb.muzzleFlashLight', function()
|
||||
local weap = net.ReadEntity()
|
||||
if not IsValid(weap) then return end
|
||||
|
||||
local dlight = DynamicLight( weap:EntIndex() )
|
||||
if dlight then
|
||||
dlight.pos = weap:GetBulletSourcePos()
|
||||
dlight.r = 255
|
||||
dlight.g = 145
|
||||
dlight.b = 10
|
||||
dlight.brightness = 1
|
||||
dlight.Decay = 6666
|
||||
dlight.Size = 512
|
||||
dlight.DieTime = CurTime() + 0.2
|
||||
end
|
||||
end)
|
||||
|
||||
function SWEP:DrawWorldModel(flags)
|
||||
self:DrawModel(flags)
|
||||
|
||||
if not self.ScopeOffset or not self.ScopeSize then return end
|
||||
if not qwb.ironsighted then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) then return end
|
||||
if owner ~= LocalPlayer() then return end
|
||||
|
||||
local scopeMat = self.ScopeMat or self.DefaultScopeMat
|
||||
|
||||
local att = self:GetAttachment( self:LookupAttachment('muzzle') )
|
||||
if not att then return end
|
||||
|
||||
local pos, ang = LocalToWorld(self.ScopeOffset, angle2, att.Pos, att.Ang)
|
||||
|
||||
local w, h = unpack(self.ScopeSize)
|
||||
local radius = math.max(w, h)
|
||||
local semiRadius = radius * 0.5
|
||||
|
||||
qwb.fullyClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilFailOperation(STENCIL_ZERO)
|
||||
render.SetStencilZFailOperation(STENCIL_ZERO)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilReferenceValue(1)
|
||||
|
||||
cam.Start3D2D(pos, ang, 0.01)
|
||||
draw.NoTexture()
|
||||
surface.SetDrawColor(color_black)
|
||||
draw_Circle(semiRadius, semiRadius, semiRadius, 30)
|
||||
cam.End3D2D()
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
cam.Start3D2D(pos, ang, 0.01)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(mat)
|
||||
surface.DrawTexturedRect(0, 0, w, h)
|
||||
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(scopeMat)
|
||||
surface.DrawTexturedRect(0, 0, w, h)
|
||||
cam.End3D2D()
|
||||
render.SetStencilEnable(false)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
35
addons/qwb/lua/weapons/weapon_base_qwb/init.lua
Normal file
35
addons/qwb/lua/weapons/weapon_base_qwb/init.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
AddCSLuaFile('cl_init.lua')
|
||||
AddCSLuaFile('shared.lua')
|
||||
|
||||
AddCSLuaFile('sh_att.lua')
|
||||
AddCSLuaFile('cl_att.lua')
|
||||
AddCSLuaFile('cl_att_menu.lua')
|
||||
|
||||
include('shared.lua')
|
||||
|
||||
include('sh_att.lua')
|
||||
include('sv_att.lua')
|
||||
|
||||
function SWEP:CreateShootRage()
|
||||
if not self.ShootRage then self.ShootRage = 0 end
|
||||
self.ShootRage = self.ShootRage + self.HorizontalRecoil / 15
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if self:GetSafetyStance() then return end
|
||||
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if qwb.isPlayerRunning(owner) then return end
|
||||
|
||||
self.Ironsighted = not self.Ironsighted
|
||||
|
||||
if self.AimSound then
|
||||
owner:EmitSound(self.AimSound, nil, nil, self.AimSoundVolume or 0.25)
|
||||
end
|
||||
|
||||
net.Start('qwb.setIronsight')
|
||||
net.WriteBool(self.Ironsighted)
|
||||
net.Send(owner)
|
||||
end
|
||||
3
addons/qwb/lua/weapons/weapon_base_qwb/sh_att.lua
Normal file
3
addons/qwb/lua/weapons/weapon_base_qwb/sh_att.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
function SWEP:GetAttach(att)
|
||||
return self._attachments and self._attachments[att]
|
||||
end
|
||||
356
addons/qwb/lua/weapons/weapon_base_qwb/shared.lua
Normal file
356
addons/qwb/lua/weapons/weapon_base_qwb/shared.lua
Normal file
@@ -0,0 +1,356 @@
|
||||
SWEP.Weight = 5
|
||||
SWEP.DrawAmmo = true
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.CSMuzzleFlashes = true
|
||||
|
||||
SWEP.Base = 'weapon_base'
|
||||
SWEP.IsQWB = true
|
||||
|
||||
SWEP.Author = 'qurs'
|
||||
SWEP.Contact = ''
|
||||
SWEP.Purpose = ''
|
||||
SWEP.Instructions = ''
|
||||
|
||||
SWEP.ViewModel = 'models/weapons/v_knife_t.mdl'
|
||||
SWEP.DefaultScopeMat = Material('materials/qwb/scope/awp.png')
|
||||
|
||||
SWEP.Category = 'qurs\' weapons base'
|
||||
|
||||
SWEP.Spawnable = false
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = 0
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = 'none'
|
||||
|
||||
SWEP.ShellType = '9mm'
|
||||
|
||||
SWEP.SafetyStanceSound = Sound('weapons/smg1/switch_single.wav')
|
||||
|
||||
local angle_zero = Angle()
|
||||
|
||||
local passiveHoldTypes = {
|
||||
revolver = 'normal',
|
||||
ar2 = 'passive',
|
||||
smg = 'passive',
|
||||
}
|
||||
|
||||
-- Thanks to octothorp team for this solution, which calculates the shot position
|
||||
local defaultBulletPosAng = {
|
||||
default = { Vector(7.7, 0.4, 3.95), Angle(-3, 5.5, 0) },
|
||||
|
||||
revolver = { Vector(7.7, 0.4, 3.95), Angle(-3, 5.5, 0) },
|
||||
ar2 = { Vector(20, -0.8, 11.2), Angle(-9.5, 0, 0) },
|
||||
smg = { Vector(14, -0.8, 6.8), Angle(-9.5, 0, 0) },
|
||||
}
|
||||
|
||||
function SWEP:CalculatePassiveHoldType()
|
||||
return passiveHoldTypes[self.HoldType] or 'normal'
|
||||
end
|
||||
|
||||
function SWEP:SafetyStanceChanged(_, old, new)
|
||||
self:GetOwner():EmitSound(self.SafetyStanceSound)
|
||||
|
||||
if new == true then
|
||||
self:SetHoldType(self.PassiveHoldType or self:CalculatePassiveHoldType())
|
||||
else
|
||||
self:SetHoldType(self.HoldType)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar('Bool', 0, 'SafetyStance')
|
||||
|
||||
self:NetworkVar('Vector', 0, 'LocalMuzzlePos')
|
||||
self:NetworkVar('Angle', 0, 'LocalMuzzleAng')
|
||||
|
||||
if SERVER then
|
||||
self:NetworkVarNotify('SafetyStance', self.SafetyStanceChanged)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType(self.HoldType)
|
||||
|
||||
local lpos, lang = unpack( defaultBulletPosAng[ self:GetHoldType() ] or defaultBulletPosAng.default )
|
||||
|
||||
self._sourceLocalMuzzlePos = self.ShootPos or lpos
|
||||
self._sourceLocalMuzzleAng = self.ShootAng or lang
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
self:SetLocalMuzzlePos(self._sourceLocalMuzzlePos)
|
||||
self:SetLocalMuzzleAng(self._sourceLocalMuzzleAng)
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if SERVER then
|
||||
self.Ironsighted = false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
self:Holster()
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) then return end
|
||||
|
||||
if owner:KeyDown(IN_USE) then return end
|
||||
if qwb.isPlayerRunning(owner) then return end
|
||||
|
||||
if not self:DefaultReload(ACT_VM_RELOAD) then return end
|
||||
owner:SetAnimation(PLAYER_RELOAD)
|
||||
|
||||
if SERVER then
|
||||
self.Ironsighted = false
|
||||
|
||||
net.Start('qwb.setIronsight')
|
||||
net.WriteBool(self.Ironsighted)
|
||||
net.Send(owner)
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + 2)
|
||||
end
|
||||
|
||||
function SWEP:GetMuzzlePos()
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) then return end
|
||||
|
||||
local att = owner:GetAttachment( owner:LookupAttachment('anim_attachment_rh') )
|
||||
if not att then return end
|
||||
|
||||
local lpos, lang = self:GetLocalMuzzlePos(), self:GetLocalMuzzleAng()
|
||||
local pos, ang = LocalToWorld(lpos, lang, att.Pos, att.Ang)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function SWEP:GetBoneAng()
|
||||
local ang = self:GetLocalMuzzleAng()
|
||||
local sourceAng = self._sourceLocalMuzzleAng
|
||||
local pitch = ang.p - sourceAng.p
|
||||
|
||||
return Angle(-pitch, 0, 0)
|
||||
end
|
||||
|
||||
function SWEP:GetBulletSourcePos()
|
||||
return self:GetMuzzlePos()
|
||||
end
|
||||
|
||||
function SWEP:ShootBullet( src, dir, num_bullets, aimcone, tracer )
|
||||
local bullet = {}
|
||||
bullet.Num = num_bullets
|
||||
bullet.Src = src
|
||||
bullet.Dir = dir
|
||||
bullet.Spread = Vector( aimcone, aimcone, 0 )
|
||||
bullet.Tracer = tracer or 5
|
||||
bullet.Force = 1
|
||||
bullet.Damage = self.Primary.Damage
|
||||
bullet.AmmoType = self.Primary.Ammo
|
||||
bullet.TracerName = self.TracerName
|
||||
|
||||
self:GetOwner():FireBullets( bullet )
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
self:ShootEffects()
|
||||
end
|
||||
|
||||
function SWEP:MuzzleFlashCustom()
|
||||
if SERVER then
|
||||
net.Start('qwb.muzzleFlashLight')
|
||||
net.WriteEntity(self)
|
||||
net.SendPVS(self:GetBulletSourcePos())
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local effectData = EffectData()
|
||||
effectData:SetEntity(self)
|
||||
effectData:SetFlags(1)
|
||||
|
||||
util.Effect('MuzzleFlash', effectData)
|
||||
end
|
||||
|
||||
function SWEP:ShellEffect()
|
||||
if SERVER then return end
|
||||
if self.NoShell then return end
|
||||
|
||||
local shellType = self.ShellType
|
||||
|
||||
local effectData = EffectData()
|
||||
|
||||
local pos = self:GetPos()
|
||||
if self.ShellOffset then
|
||||
local att = self:GetAttachment( self:LookupAttachment('muzzle') )
|
||||
if att then
|
||||
pos = LocalToWorld(self.ShellOffset, angle_zero, att.Pos, att.Ang)
|
||||
end
|
||||
end
|
||||
|
||||
effectData:SetOrigin(pos)
|
||||
effectData:SetFlags(self.ShellVelocity or 75)
|
||||
|
||||
util.Effect('EjectBrass_' .. shellType, effectData)
|
||||
end
|
||||
|
||||
function SWEP:ShootEffects()
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
|
||||
self:MuzzleFlashCustom()
|
||||
self:ShellEffect()
|
||||
|
||||
self:EmitSound( self.Primary.Sound )
|
||||
|
||||
self.RecoilAnimBack = nil
|
||||
self.RecoilAnim = true
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
if not IsValid(self) or not IsValid(self:GetOwner()) then return end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local pos, ang = self:GetBulletSourcePos()
|
||||
if not pos or not ang then return end
|
||||
|
||||
local forward = ang:Forward()
|
||||
|
||||
owner:LagCompensation(true)
|
||||
self:ShootBullet(pos, forward, self.Primary.NumShots or 1, 0, 1) -- pre-last self.Primary.Spread or 0.01
|
||||
owner:LagCompensation(false)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
|
||||
|
||||
if SERVER then self:CreateShootRage() end
|
||||
|
||||
-- if not self.IronSighted and self.HipFireRecoil then
|
||||
-- local pitch = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
|
||||
-- local yaw = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
|
||||
-- local roll = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
|
||||
|
||||
-- owner:SetViewPunchAngles(Angle(pitch, yaw, roll))
|
||||
-- end
|
||||
|
||||
if self.PostPrimaryAttack then self:PostPrimaryAttack() end
|
||||
end
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
if self:GetSafetyStance() then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(owner) then return end
|
||||
|
||||
if qwb.isPlayerRunning(owner) then return end
|
||||
|
||||
if self:Clip1() <= 0 then
|
||||
self:EmitSound('weapons/clipempty_rifle.wav')
|
||||
self:SetNextPrimaryFire(CurTime() + 0.7)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if owner:WaterLevel() > 2 then return false end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
local owner = self:GetOwner()
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
|
||||
if owner:KeyDown(IN_USE) and owner:KeyDown(IN_RELOAD) and (not self.SafetyStanceCD or CurTime() >= self.SafetyStanceCD) then
|
||||
self.SafetyStanceCD = CurTime() + 0.4
|
||||
self:SetSafetyStance( not self:GetSafetyStance() )
|
||||
end
|
||||
|
||||
local passiveHoldType = self.PassiveHoldType or self:CalculatePassiveHoldType()
|
||||
if qwb.isPlayerRunning(owner) and self:GetHoldType() ~= passiveHoldType then
|
||||
self:SetHoldType(passiveHoldType)
|
||||
|
||||
if self.Ironsighted then self.Ironsighted = false end
|
||||
elseif not qwb.isPlayerRunning(owner) and not self:GetSafetyStance() and self:GetHoldType() == passiveHoldType then
|
||||
self:SetHoldType(self.HoldType)
|
||||
end
|
||||
|
||||
if not self.ShootRageDelta then self.ShootRageDelta = 0 end
|
||||
|
||||
if self.ShootRage and self.ShootRage > 0 then
|
||||
self.ShootRageDelta = self.ShootRageDelta + 0.2
|
||||
|
||||
self.ShootRage = self.ShootRage - 0.05
|
||||
if self.ShootRage < 0 then self.ShootRage = 0 end
|
||||
else
|
||||
self.ShootRageDelta = 0
|
||||
end
|
||||
|
||||
if self.RecoilAnim then
|
||||
local bone = owner:LookupBone('ValveBiped.Bip01_R_Hand')
|
||||
local bone2 = owner:LookupBone('ValveBiped.Bip01_R_UpperArm')
|
||||
local needle = Angle(self.Recoil / 50 * 90, 0, 0)
|
||||
local needle2 = Angle(0, (self.ShootRage or 0) * math.sin(self.ShootRageDelta or 0), 0)
|
||||
|
||||
owner:ManipulateBoneAngles( bone, LerpAngle(0.8, owner:GetManipulateBoneAngles(bone), needle), true )
|
||||
owner:ManipulateBoneAngles( bone2, LerpAngle(0.45, owner:GetManipulateBoneAngles(bone2), needle2), true )
|
||||
|
||||
local ang = owner:GetManipulateBoneAngles(bone)
|
||||
if math.abs(ang[1] - needle[1]) <= 0.1 then
|
||||
self.RecoilAnim = nil
|
||||
self.RecoilAnimBack = true
|
||||
end
|
||||
elseif self.RecoilAnimBack then
|
||||
local bone = owner:LookupBone('ValveBiped.Bip01_R_Hand')
|
||||
local bone2 = owner:LookupBone('ValveBiped.Bip01_R_UpperArm')
|
||||
local needle = Angle(0, 0, 0)
|
||||
local needle2 = Angle(0, (self.ShootRage or 0) * math.sin(self.ShootRageDelta or 0), 0)
|
||||
|
||||
owner:ManipulateBoneAngles( bone, LerpAngle(0.1, owner:GetManipulateBoneAngles(bone), needle), true )
|
||||
owner:ManipulateBoneAngles( bone2, LerpAngle(0.1, owner:GetManipulateBoneAngles(bone2), needle2), true )
|
||||
|
||||
local ang = owner:GetManipulateBoneAngles(bone)
|
||||
if math.abs(ang[1] - needle[1]) <= 0.1 then
|
||||
self.RecoilAnimBack = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- if CLIENT then
|
||||
-- local bone = owner:LookupBone('ValveBiped.Bip01_R_Hand')
|
||||
-- local ang = self:GetBoneAng()
|
||||
-- owner:ManipulateBoneAngles(bone, ang)
|
||||
-- end
|
||||
|
||||
-- if CLIENT then return end
|
||||
|
||||
-- if owner.RecoilAnim then
|
||||
-- local curAng = self:GetLocalMuzzleAng()
|
||||
-- local sourceAng = self._sourceLocalMuzzleAng
|
||||
|
||||
-- local needle = Angle(sourceAng[1] - (self.Recoil / 50 * 90), curAng[2], curAng[3])
|
||||
|
||||
-- self:SetLocalMuzzleAng( LerpAngle(0.8, self:GetLocalMuzzleAng(), needle) )
|
||||
|
||||
-- local ang = self:GetLocalMuzzleAng()
|
||||
-- if math.abs(ang[1] - needle[1]) <= 0.1 then
|
||||
-- owner.RecoilAnim = nil
|
||||
-- owner.RecoilAnimBack = true
|
||||
-- end
|
||||
-- elseif owner.RecoilAnimBack then
|
||||
-- local needle = self._sourceLocalMuzzleAng
|
||||
|
||||
-- self:SetLocalMuzzleAng( LerpAngle(0.025, self:GetLocalMuzzleAng(), needle) )
|
||||
|
||||
-- local ang = self:GetLocalMuzzleAng()
|
||||
-- if math.abs(ang[1] - needle[1]) <= 0.1 then
|
||||
-- owner.RecoilAnimBack = nil
|
||||
-- end
|
||||
-- end
|
||||
end
|
||||
52
addons/qwb/lua/weapons/weapon_base_qwb/sv_att.lua
Normal file
52
addons/qwb/lua/weapons/weapon_base_qwb/sv_att.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
function SWEP:CanAttach(attachType, attachID)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:SetAttach(attachType, attachID)
|
||||
if not self.Attachments[attachType] or not self.Attachments[attachType][attachID] then return end
|
||||
|
||||
self._attachments = self._attachments or {}
|
||||
|
||||
if self._attachments[attachType] == attachID then return end
|
||||
if not self:CanAttach(attachType, attachID) then return end
|
||||
|
||||
self._attachments[attachType] = attachID
|
||||
|
||||
net.Start('qwb.setAttachment')
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(attachType)
|
||||
net.WriteString(attachID)
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
function SWEP:RemoveAttach(attachType)
|
||||
if not self._attachments then return end
|
||||
if not self._attachments[attachType] then return end
|
||||
|
||||
self._attachments[attachType] = nil
|
||||
|
||||
net.Start('qwb.removeAttachment')
|
||||
net.WriteEntity(self)
|
||||
net.WriteString(attachType)
|
||||
net.Broadcast()
|
||||
end
|
||||
|
||||
net.Receive('qwb.setAttachment', function(_, ply)
|
||||
local weap = ply:GetActiveWeapon()
|
||||
if not IsValid(weap) or not weap.IsQWB or not weap.SetAttach then return end
|
||||
|
||||
local attachType, attachID = net.ReadString(), net.ReadString()
|
||||
if not attachType or not attachID then return end
|
||||
|
||||
weap:SetAttach(attachType, attachID)
|
||||
end)
|
||||
|
||||
net.Receive('qwb.removeAttachment', function(_, ply)
|
||||
local weap = ply:GetActiveWeapon()
|
||||
if not IsValid(weap) or not weap.IsQWB or not weap.RemoveAttach then return end
|
||||
|
||||
local attachType = net.ReadString()
|
||||
if not attachType then return end
|
||||
|
||||
weap:RemoveAttach(attachType)
|
||||
end)
|
||||
Reference in New Issue
Block a user