Files
wnsrc/lua/entities/lvs_base/sh_weapons.lua

543 lines
13 KiB
Lua
Raw Permalink Normal View History

2024-08-04 23:54:45 +03:00
--[[
| 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/
--]]
ENT.WEAPONS = {
[1] = {},
}
function ENT:InitWeapons()
end
function ENT:AddWeapon( weaponData, PodID )
if not istable( weaponData ) then print("[LVS] couldn't register weapon") return end
local data = table.Copy( weaponData )
if not PodID or PodID <= 1 then
PodID = 1
end
if not self.WEAPONS[ PodID ] then
self.WEAPONS[ PodID ] = {}
end
local default = LVS:GetWeaponPreset( "DEFAULT" )
data.Icon = data.Icon or Material("lvs/weapons/bullet.png")
data.Ammo = data.Ammo or -1
data.Delay = data.Delay or 0
data.HeatRateUp = data.HeatRateUp or default.HeatRateUp
data.Attack = data.Attack or default.Attack
data.StartAttack = data.StartAttack or default.StartAttack
data.FinishAttack = data.FinishAttack or default.FinishAttack
data.OnSelect = data.OnSelect or default.OnSelect
data.OnDeselect = data.OnDeselect or default.OnDeselect
data.OnThink = data.OnThink or default.OnThink
data.OnOverheat = data.OnOverheat or default.OnOverheat
data.OnRemove = data.OnRemove or default.OnRemove
data.UseableByAI = data.UseableByAI ~= false
table.insert( self.WEAPONS[ PodID ], data )
end
function ENT:HasWeapon( ID )
return istable( self.WEAPONS[1][ ID ] )
end
function ENT:AIHasWeapon( ID )
local weapon = self.WEAPONS[1][ ID ]
if not istable( weapon ) then return false end
return weapon.UseableByAI
end
function ENT:GetActiveWeapon()
local SelectedID = self:GetSelectedWeapon()
local CurWeapon = self.WEAPONS[1][ SelectedID ]
return CurWeapon, SelectedID
end
function ENT:GetMaxAmmo()
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return -1 end
return CurWeapon.Ammo or -1
end
if SERVER then
function ENT:WeaponRestoreAmmo()
local AmmoIsSet = false
for PodID, data in pairs( self.WEAPONS ) do
for id, weapon in pairs( data ) do
local MaxAmmo = weapon.Ammo or -1
local CurAmmo = weapon._CurAmmo or -1
if CurAmmo == MaxAmmo then continue end
self.WEAPONS[PodID][ id ]._CurAmmo = MaxAmmo
AmmoIsSet = true
end
end
if AmmoIsSet then
self:SetNWAmmo( self:GetAmmo() )
for _, pod in pairs( self:GetPassengerSeats() ) do
local weapon = pod:lvsGetWeapon()
if not IsValid( weapon ) then continue end
weapon:SetNWAmmo( weapon:GetAmmo() )
end
end
return AmmoIsSet
end
function ENT:WeaponsOnRemove()
for _, data in pairs( self.WEAPONS ) do
for ID, Weapon in pairs( data ) do
if not Weapon.OnRemove then continue end
Weapon.OnRemove( self )
end
end
end
function ENT:WeaponsFinish()
if not self._activeWeapon then return end
local CurWeapon = self.WEAPONS[1][ self._activeWeapon ]
if not CurWeapon then return end
if CurWeapon.FinishAttack then
CurWeapon.FinishAttack( self )
end
self._activeWeapon = nil
self.OldAttack = false
end
function ENT:GetAmmo()
if self:GetAI() then return self:GetMaxAmmo() end
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return -1 end
return CurWeapon._CurAmmo or self:GetMaxAmmo()
end
function ENT:TakeAmmo( num )
if self:GetMaxAmmo() <= 0 then return end
local CurWeapon = self:GetActiveWeapon()
CurWeapon._CurAmmo = math.max( self:GetAmmo() - (num or 1), 0 )
self:SetNWAmmo( CurWeapon._CurAmmo )
end
function ENT:GetHeat()
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return 0 end
return (CurWeapon._CurHeat or 0)
end
function ENT:GetOverheated()
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return false end
return CurWeapon.Overheated == true
end
function ENT:SetOverheated( overheat )
if self:GetOverheated() == overheat then return end
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return end
CurWeapon.Overheated = overheat
if self:GetHeat() == 0 then return end
if CurWeapon.OnOverheat then
CurWeapon.OnOverheat( self )
end
end
function ENT:SetHeat( heat )
local CurWeapon = self:GetActiveWeapon()
if not CurWeapon then return end
heat = math.Clamp( heat, 0, 1 )
CurWeapon._CurHeat = heat
if self:GetNWHeat() == heat then return end
self:SetNWHeat( heat )
end
function ENT:CanAttack()
local CurWeapon = self:GetActiveWeapon()
return (CurWeapon._NextFire or 0) < CurTime()
end
function ENT:SetNextAttack( time )
local CurWeapon = self:GetActiveWeapon()
CurWeapon._NextFire = time
end
function ENT:WeaponsShouldFire()
if self:GetAI() then return self._AIFireInput end
local ply = self:GetDriver()
if not IsValid( ply ) then return false end
return ply:lvsKeyDown( "ATTACK" )
end
function ENT:WeaponsThink()
local EntTable = self:GetTable()
local T = CurTime()
local FT = FrameTime()
local CurWeapon, SelectedID = self:GetActiveWeapon()
for ID, Weapon in pairs( self.WEAPONS[1] ) do
local IsActive = ID == SelectedID
if Weapon.OnThink then Weapon.OnThink( self, IsActive ) end
if IsActive then continue end
-- cool all inactive weapons down
Weapon._CurHeat = Weapon._CurHeat and Weapon._CurHeat - math.min( Weapon._CurHeat, (Weapon.HeatRateDown or 0.25) * FT ) or 0
end
if not CurWeapon then return end
local ShouldFire = self:WeaponsShouldFire()
local CurHeat = self:GetHeat()
if self:GetOverheated() then
if CurHeat <= 0 then
self:SetOverheated( false )
else
ShouldFire = false
end
else
if CurHeat >= 1 then
self:SetOverheated( true )
ShouldFire = false
end
end
if self:GetMaxAmmo() > 0 then
if self:GetAmmo() <= 0 then
ShouldFire = false
end
end
if ShouldFire ~= EntTable.OldAttack then
EntTable.OldAttack = ShouldFire
if ShouldFire then
if CurWeapon.StartAttack then
CurWeapon.StartAttack( self )
end
EntTable._activeWeapon = SelectedID
else
self:WeaponsFinish()
end
end
if ShouldFire then
if not self:CanAttack() then return end
local ShootDelay = (CurWeapon.Delay or 0)
self:SetNextAttack( T + ShootDelay )
self:SetHeat( CurHeat + (CurWeapon.HeatRateUp or 0.2) * math.max(ShootDelay, FT) )
if not CurWeapon.Attack then return end
if CurWeapon.Attack( self ) then
self:SetHeat( CurHeat - math.min( self:GetHeat(), (CurWeapon.HeatRateDown or 0.25) * FT ) )
self:SetNextAttack( T )
end
EntTable._lvsNextActiveWeaponCoolDown = T + 0.25
else
if (EntTable._lvsNextActiveWeaponCoolDown or 0) > T then return end
self:SetHeat( self:GetHeat() - math.min( self:GetHeat(), (CurWeapon.HeatRateDown or 0.25) * FT ) )
end
end
function ENT:SelectWeapon( ID )
if not isnumber( ID ) then return end
if self.WEAPONS[1][ ID ] then
self:SetSelectedWeapon( ID )
end
local ply = self:GetDriver()
if not IsValid( ply ) then return end
net.Start( "lvs_select_weapon" )
net.Send( ply )
end
function ENT:OnWeaponChanged( name, old, new)
if new == old then return end
self:WeaponsFinish()
local PrevWeapon = self.WEAPONS[1][ old ]
if PrevWeapon and PrevWeapon.OnDeselect then
PrevWeapon.OnDeselect( self, new )
end
local NextWeapon = self.WEAPONS[1][ new ]
if NextWeapon and NextWeapon.OnSelect then
NextWeapon.OnSelect( self, old )
self:SetNWAmmo( NextWeapon._CurAmmo or NextWeapon.Ammo or -1 )
end
end
return
end
function ENT:DrawWeaponIcon( PodID, ID, x, y, width, height, IsSelected, IconColor )
end
function ENT:SelectWeapon( ID )
if not isnumber( ID ) then return end
net.Start( "lvs_select_weapon" )
net.WriteInt( ID, 5 )
net.WriteBool( false )
net.SendToServer()
end
function ENT:NextWeapon()
net.Start( "lvs_select_weapon" )
net.WriteInt( 1, 5 )
net.WriteBool( true )
net.SendToServer()
end
function ENT:PrevWeapon()
net.Start( "lvs_select_weapon" )
net.WriteInt( -1, 5 )
net.WriteBool( true )
net.SendToServer()
end
LVS:AddHudEditor( "WeaponSwitcher", ScrW() - 210, ScrH() - 165, 200, 68, 200, 68, "WEAPON SELECTOR",
function( self, vehicle, X, Y, W, H, ScrX, ScrY, ply )
if not vehicle.LVSHudPaintWeapons then return end
vehicle:LVSHudPaintWeapons( X, Y, W, H, ScrX, ScrY, ply )
end
)
LVS:AddHudEditor( "WeaponInfo", ScrW() - 230, ScrH() - 85, 220, 75, 220, 75, "WEAPON INFO",
function( self, vehicle, X, Y, W, H, ScrX, ScrY, ply )
if not vehicle.LVSHudPaintWeaponInfo then return end
vehicle:LVSHudPaintWeaponInfo( X, Y, W, H, ScrX, ScrY, ply )
end
)
function ENT:GetAmmoID( ID )
local ply = LocalPlayer()
if not IsValid( ply ) then return end
local Base = ply:lvsGetWeaponHandler()
if not IsValid( Base ) then return -1 end
local selected = Base:GetSelectedWeapon()
local weapon = self.WEAPONS[ Base:GetPodIndex() ][ ID ]
if ID == selected then
weapon._CurAmmo = Base:GetNWAmmo()
else
weapon._CurAmmo = weapon._CurAmmo or weapon.Ammo or -1
end
return weapon._CurAmmo
end
local Circles = {
[1] = {r = -1, col = Color(0,0,0,200)},
[2] = {r = 0, col = Color(255,255,255,200)},
[3] = {r = 1, col = Color(255,255,255,255)},
[4] = {r = 2, col = Color(255,255,255,200)},
[5] = {r = 3, col = Color(0,0,0,200)},
}
local function DrawCircle( X, Y, target_radius, heatvalue )
local endang = 360 * heatvalue
if endang == 0 then return end
for i = 1, #Circles do
local data = Circles[ i ]
local radius = target_radius + data.r
local segmentdist = endang / ( math.pi * radius / 2 )
for a = 0, endang, segmentdist do
local r = data.col.r
local g = data.col.g * (1 - math.min(a / 270,1))
local b = data.col.b * (1 - math.min(a / 90,1))
surface.SetDrawColor( r, g, b, data.col.a )
surface.DrawLine( X - math.sin( math.rad( a ) ) * radius, Y + math.cos( math.rad( a ) ) * radius, X - math.sin( math.rad( a + segmentdist ) ) * radius, Y + math.cos( math.rad( a + segmentdist ) ) * radius )
end
end
end
ENT.HeatMat = Material( "lvs/heat.png" )
function ENT:LVSHudPaintWeaponInfo( X, Y, w, h, ScrX, ScrY, ply )
local Base = ply:lvsGetWeaponHandler()
if not IsValid( Base ) then return end
if not Base:HasWeapon( Base:GetSelectedWeapon() ) then return end
local Heat = Base:GetNWHeat()
local hX = X + w - h * 0.5
local hY = Y + h * 0.25 + h * 0.25
local hAng = math.cos( CurTime() * 50 ) * 5 * Heat ^ 2
surface.SetMaterial( self.HeatMat )
surface.SetDrawColor( 0, 0, 0, 200 )
surface.DrawTexturedRectRotated( hX + 4, hY + 1, h * 0.5, h * 0.5, hAng )
surface.SetDrawColor( 255, 255 * (1 - Heat), 255 * math.max(1 - Heat * 1.5,0), 255 )
surface.DrawTexturedRectRotated( hX + 2, hY - 1, h * 0.5, h * 0.5, hAng )
DrawCircle( hX, hY, h * 0.35, Heat )
if Base:GetMaxAmmo() <= 0 then return end
draw.DrawText( "AMMO ", "LVS_FONT", X + 72, Y + 35, color_white, TEXT_ALIGN_RIGHT )
draw.DrawText( Base:GetNWAmmo(), "LVS_FONT_HUD_LARGE", X + 72, Y + 20, color_white, TEXT_ALIGN_LEFT )
end
function ENT:LVSHudPaintWeapons( X, Y, w, h, ScrX, ScrY, ply )
local EntTable = self:GetTable()
local Base = ply:lvsGetWeaponHandler()
if not IsValid( Base ) then return end
local Pod = ply:GetVehicle()
if not IsValid( Pod ) then return end
local PodID = Base:GetPodIndex()
local num = #self.WEAPONS[ PodID ]
if num <= 1 then return end
local CenterY = (Y + h * 0.5)
local CenterX = (X + w * 0.5)
local FlatSelector = CenterX > ScrX * 0.333 and CenterX < ScrX * 0.666
local T = CurTime()
local FT = RealFrameTime()
local gap = 4
local SizeY = h - gap
local Selected = Base:GetSelectedWeapon()
if Selected ~= EntTable._OldSelected then
EntTable._OldSelected = Selected
Pod._SelectActiveTime = T + 2
end
local tAlpha = (Pod._SelectActiveTime or 0) > T and 1 or 0
local tAlphaRate = FT * 15
EntTable.smAlphaSW = EntTable.smAlphaSW and (EntTable.smAlphaSW + math.Clamp(tAlpha - EntTable.smAlphaSW,-tAlphaRate,tAlphaRate)) or 0
if EntTable.smAlphaSW > 0.95 then
EntTable._DisplaySelected = Selected
else
EntTable._DisplaySelected = EntTable._DisplaySelected or Selected
end
local A255 = 255 * EntTable.smAlphaSW
local A150 = 150 * EntTable.smAlphaSW
local Col = Color(0,0,0,A150)
local ColSelect = Color(255,255,255,A150)
local SwapY = 0
if Y < (ScrY * 0.5 - h * 0.5) then
SwapY = 1
end
for ID = 1, num do
local IsSelected = EntTable._DisplaySelected == ID
local n = num - ID
local xPos = FlatSelector and X + (w + gap) * (ID - 1) - ((w + gap) * 0.5 * num - w * 0.5) or X
local yPos = FlatSelector and Y - h * math.min(SwapY,0) or Y - h * n + (num - 1) * h * SwapY
draw.RoundedBox(5, xPos, yPos, w, SizeY, IsSelected and ColSelect or Col )
if IsSelected then
surface.SetDrawColor( 0, 0, 0, A255 )
else
surface.SetDrawColor( 255, 255, 255, A255 )
end
if isbool( EntTable.WEAPONS[PodID][ID].Icon ) then
local col = IsSelected and Color(255,255,255,A255) or Color(0,0,0,A255)
self:DrawWeaponIcon( PodID, ID, xPos, yPos, SizeY * 2, SizeY, IsSelected, col )
else
surface.SetMaterial( self.WEAPONS[PodID][ID].Icon )
surface.DrawTexturedRect( xPos, yPos, SizeY * 2, SizeY )
end
local ammo = self:GetAmmoID( ID )
if ammo > -1 then
draw.DrawText( ammo, "LVS_FONT_HUD", xPos + w - 10, yPos + SizeY * 0.5 - 10, IsSelected and Color(0,0,0,A255) or Color(255,255,255,A255), TEXT_ALIGN_RIGHT )
else
draw.DrawText( "O", "LVS_FONT_HUD", xPos + w - 19, yPos + SizeY * 0.5 - 10, IsSelected and Color(0,0,0,A255) or Color(255,255,255,A255), TEXT_ALIGN_RIGHT )
draw.DrawText( "O", "LVS_FONT_HUD", xPos + w - 10, yPos + SizeY * 0.5 - 10, IsSelected and Color(0,0,0,A255) or Color(255,255,255,A255), TEXT_ALIGN_RIGHT )
end
end
end