mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
730 lines
23 KiB
Lua
730 lines
23 KiB
Lua
|
|
--[[
|
||
|
|
| 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/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
AddCSLuaFile()
|
||
|
|
AddCSLuaFile("includes/jakubbaku_utils.lua")
|
||
|
|
include("includes/jakubbaku_utils.lua")
|
||
|
|
|
||
|
|
ENT.Type = "anim"
|
||
|
|
ENT.PrintName = "Emplacement Base"
|
||
|
|
ENT.Category = "Jakub Baku"
|
||
|
|
ENT.Spawnable = false
|
||
|
|
ENT.AdminOnly = false
|
||
|
|
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||
|
|
ENT.AutomaticFrameAdvance = true
|
||
|
|
|
||
|
|
/*
|
||
|
|
--------- DEV HELP README ---------
|
||
|
|
|
||
|
|
Mannable sentry/turret/whatever-you-gonna-call-it base, made by me - Jakub Baku / Geiger 21 / AwesomeGraczGie21 / karolek471 (I go by many names :P)
|
||
|
|
It's purpose is to facilitate the creation of new "mannables" for my addon, but I thought I can share my work with you.
|
||
|
|
|
||
|
|
How to use?
|
||
|
|
- Put the ent_mannable_bakubase.lua file in lua/entities
|
||
|
|
- Put the jakubbaku_utils.lua in lua/includes
|
||
|
|
- You can also put effects in lua/effects
|
||
|
|
- Create a new LUA file called along the lines of "entity_NAME" (make it unique) in lua/entities folder
|
||
|
|
- Add this "boiler plate" code:
|
||
|
|
|
||
|
|
AddCSLuaFile()
|
||
|
|
|
||
|
|
ENT.Base = "ent_mannable_bakubase" //important!
|
||
|
|
ENT.PrintName = "Your gun name"
|
||
|
|
ENT.Category = "Your category"
|
||
|
|
ENT.Spawnable = true //true if it's spawnable in the spawn menu
|
||
|
|
ENT.AdminOnly = false //true if it should be spawnable only for admins
|
||
|
|
|
||
|
|
Since we're working with a base we don't want to override default hooks like ENT:Initialize(), so please,
|
||
|
|
use only the ones provided by the base unless you know what you're doing.
|
||
|
|
|
||
|
|
(SHARED - accessible both on client and server
|
||
|
|
SERVER - serverside only
|
||
|
|
CLIENT - clientside only)
|
||
|
|
|
||
|
|
--------------- Hooks provided by the base (SIDE, name, return type): ---------------
|
||
|
|
SHARED ENT:DoInit() void
|
||
|
|
Called when the entity is spawned
|
||
|
|
|
||
|
|
SHARED ENT:DoRemove() void
|
||
|
|
Called when the entity is about to get removed
|
||
|
|
|
||
|
|
SHARED ENT:OnActivateGun() void
|
||
|
|
Called when the user starts using the gun or enters the vehicle on which the gun is mounted
|
||
|
|
|
||
|
|
SHARED ENT:OnDeactivateGun() void
|
||
|
|
Called when the user dies, gets too far from the gun, exits the vehicle etc.
|
||
|
|
|
||
|
|
SERVER ENT:OnStartShooting() void
|
||
|
|
Called when the user starts firing
|
||
|
|
|
||
|
|
SERVER ENT:OnStopShooting() void
|
||
|
|
Called when the user stops firing
|
||
|
|
|
||
|
|
SERVER ENT:DoShootThink() boolean
|
||
|
|
Called everytime the user fires. Return true to override the default firing function
|
||
|
|
|
||
|
|
SERVER ENT:OnStartAttack() void
|
||
|
|
Called when the user clicks the Left mouse button. Most of the time it's
|
||
|
|
identical to OnStartShooting, but using this function you can delay the firing,
|
||
|
|
for example in case of charging the gun or something
|
||
|
|
|
||
|
|
SERVER ENT:OnStopAttack() void
|
||
|
|
Called when the user lets go of the left mouse button. Most of the time it's
|
||
|
|
identical to OnStopShooting
|
||
|
|
|
||
|
|
SERVER ENT:DoShoot(direction) void
|
||
|
|
Called when the user fires the gun, use the direction argument to direct your bullets, projectiles.
|
||
|
|
direction is a normalized direction vector pointing in the aim direction
|
||
|
|
|
||
|
|
CLIENT ENT:DoNotification() void
|
||
|
|
Called when the user starts using the gun. It's purpose is to
|
||
|
|
display the help notification (ENT._Notification)
|
||
|
|
|
||
|
|
CLIENT ENT:DoDraw() void
|
||
|
|
Called every frame. Used for drawing effects, models etc.
|
||
|
|
|
||
|
|
CLIENT ENT:DoThink() void
|
||
|
|
Called every frame
|
||
|
|
|
||
|
|
--------------- Methods provided by the base ---------------
|
||
|
|
SERVER ENT:BakuRegisterMannable() void
|
||
|
|
Registers the gun for use in vehicles. If you want your gun to be
|
||
|
|
able to be mounted on the vehicle call this function, preferably in ENT:DoInit() hook.
|
||
|
|
|
||
|
|
SERVER ENT:BakuManned(manned (boolean)) void
|
||
|
|
INTERNAL, DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING
|
||
|
|
Use this method to mark the user as "not manning the gun" (manned = false) or "manning the gun" (manned = true)
|
||
|
|
|
||
|
|
SERVER ENT:BakuIsManned(user) boolean
|
||
|
|
INTERNAL, DO NOT USE UNLESS YOU KNOW WHAT YOU'RE DOING
|
||
|
|
Tells whether the user is manning a gun
|
||
|
|
|
||
|
|
CLIENT ENT:SetupCustomModel(mdl (string), bone (number), rendergroup (RENDERGROUP_ enum)) CSEnt
|
||
|
|
Facilitates the creation of ENT._CustomGunModel. Mdl is a path to model like "models/weapons/something.mdl",
|
||
|
|
bone is a boneID of the bone used for positioning the model, rendergroup by default is RENDERGROUP_TRANSLUCENT
|
||
|
|
|
||
|
|
--------------- Important variables (type, name) ---------------
|
||
|
|
Please do not modify other base-specific variables than those specified there
|
||
|
|
|
||
|
|
number ENT.ShootDelay
|
||
|
|
Used by default shooting code. Basically a delay between shots
|
||
|
|
|
||
|
|
number ENT._ShootTimer
|
||
|
|
Internal, used for timing the shots. It's handy for charged attack, here's example
|
||
|
|
|
||
|
|
function ENT:OnStartAttack()
|
||
|
|
//when the user starts attacking
|
||
|
|
|
||
|
|
local somechargetime = 1 //1 second charge time
|
||
|
|
|
||
|
|
self:EmitSound("some/sound.wav") //we emit some sound
|
||
|
|
self._ShootTimer = CurTime() + somechargetime
|
||
|
|
|
||
|
|
//the CurTime() is really important here, because it's not a simple delay, it's a timestamp
|
||
|
|
//of the next fire
|
||
|
|
end
|
||
|
|
|
||
|
|
number ENT._Ammo
|
||
|
|
If set to less than 0 (-1 for example) the gun has unlimited ammo.
|
||
|
|
|
||
|
|
boolean ENT._DoNetworking
|
||
|
|
true by default. If set to false many shared hooks won't be called clientside
|
||
|
|
|
||
|
|
boolean ENT._IsShooting
|
||
|
|
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||
|
|
Handy for determining whether the gun is firing or not
|
||
|
|
|
||
|
|
boolean ENT._Active
|
||
|
|
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||
|
|
Tells whether the gun is actively manned / used
|
||
|
|
|
||
|
|
boolean ENT._DriveMode
|
||
|
|
READ ONLY VARIABLE, do not modify unless you know what you're doing.
|
||
|
|
Tells whether the gun is in drive mode (mounted to a vehicle)
|
||
|
|
|
||
|
|
boolean ENT._HideGunModel
|
||
|
|
Set it in ENT:DoInit() to true to hide the original
|
||
|
|
gun model
|
||
|
|
|
||
|
|
CSEnt ENT._CustomGunModel CLIENTSIDE ONLY
|
||
|
|
A ClientsideModel representing the custom gun model.
|
||
|
|
Set it in clientside ENT:DoInit() hook like that:
|
||
|
|
self._CustomGunModel = ClientsideModel("path/to/model.mdl")
|
||
|
|
Preferably use ENT:SetupCustomModel method
|
||
|
|
|
||
|
|
number ENT._CModelBone CLIENTSIDE ONLY
|
||
|
|
Bone ID of a _CustomGunModel's bone used to change the position.
|
||
|
|
Most of the times you should not touch it (it's 0 - ROOT_BONE by default)
|
||
|
|
|
||
|
|
VMatrix ENT._GunModelMatrix CLIENTSIDE ONLY
|
||
|
|
Transformation matrix of a gun model. Used for positioning, changing
|
||
|
|
the angles of a custom gun model. If not touched it's identity matrix,
|
||
|
|
so no changes to the pos/ang/scale
|
||
|
|
|
||
|
|
|
||
|
|
Why don't I make accessor funcs for all those obscure variables? Well... I don't need them.
|
||
|
|
Real programming is when you can break all your code with just one missplaced variable ;)
|
||
|
|
This is base for smart people, cautious programmers. But no, seriously, it's because
|
||
|
|
I don't need it
|
||
|
|
|
||
|
|
--------/ DEV HELP README \--------
|
||
|
|
*/
|
||
|
|
|
||
|
|
hook.Add("InitPostEntity", "MannableBakuBaseDuplicator", function()
|
||
|
|
local _base = scripted_ents.Get("ent_mannable_bakubase")
|
||
|
|
|
||
|
|
local _regents = scripted_ents.GetList()
|
||
|
|
for k, v in pairs(_regents) do
|
||
|
|
if(v.Base == "ent_mannable_bakubase") then
|
||
|
|
duplicator.RegisterEntityClass(v.t.ClassName, _base.BaseDupeFunction, "Data")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
function ENT:DoInit() end
|
||
|
|
function ENT:DoRemove() end
|
||
|
|
function ENT:DoSetupDataTables() end
|
||
|
|
function ENT.DupeFunction(ply, data) end
|
||
|
|
|
||
|
|
function ENT:RegisterDuplicator()
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:SetupDataTables()
|
||
|
|
if(self._CanAIControlled) then
|
||
|
|
self:NetworkVar("Bool", 31, "_AIControlled", {KeyName = "aicontrolled", Edit = {title = "AI Controlled", category = "AI", type = "Boolean", order = 0}})
|
||
|
|
|
||
|
|
if(SERVER) then
|
||
|
|
self:Set_AIControlled(false)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:NetworkVarNotify("_AIControlled", self.HandleAIVarChange)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:DoSetupDataTables()
|
||
|
|
end
|
||
|
|
|
||
|
|
if (SERVER) then
|
||
|
|
function ENT.BaseDupeFunction(ply, data)
|
||
|
|
data._User = NULL
|
||
|
|
data._Active = false
|
||
|
|
data._ShootTimer = 0
|
||
|
|
data._UseTimer = 0
|
||
|
|
data._SequenceTimer = 0
|
||
|
|
data._IsShooting = false
|
||
|
|
|
||
|
|
local _func = scripted_ents.Get(data.Class).DupeFunction
|
||
|
|
|
||
|
|
if(isfunction(_func)) then
|
||
|
|
_func(ply, data)
|
||
|
|
end
|
||
|
|
|
||
|
|
return duplicator.GenericDuplicatorFunction(ply, data)
|
||
|
|
end
|
||
|
|
|
||
|
|
ENT._User = NULL
|
||
|
|
ENT._UserPrevWeapon = NULL
|
||
|
|
ENT._Active = false
|
||
|
|
ENT._DriveMode = false
|
||
|
|
ENT._Vehicle = NULL
|
||
|
|
ENT.ShootDelay = 0.075
|
||
|
|
ENT._Ammo = -1
|
||
|
|
|
||
|
|
ENT._OldAim = Vector(0, 0, 0)
|
||
|
|
|
||
|
|
ENT._ShootTimer = 0
|
||
|
|
ENT._UseTimer = 0
|
||
|
|
ENT._SequenceTimer = 0
|
||
|
|
ENT._IsShooting = false
|
||
|
|
ENT._HideGunModel = false
|
||
|
|
ENT._Automatic = true
|
||
|
|
ENT._DoNetworking = true
|
||
|
|
ENT._PitchOffset = 0
|
||
|
|
|
||
|
|
//AI
|
||
|
|
ENT._AIControlled = false
|
||
|
|
ENT._AIShooting = false
|
||
|
|
ENT._AIAimPoint = Vector(0, 0, 0)
|
||
|
|
ENT._AIEnemy = NULL
|
||
|
|
|
||
|
|
local _varhandlers = {
|
||
|
|
["_AIControlled"] = function(self, old, new)
|
||
|
|
self:InitAIControll()
|
||
|
|
end,
|
||
|
|
}
|
||
|
|
|
||
|
|
function ENT:HandleAIVarChange(name, old, new)
|
||
|
|
if(isfunction(_varhandlers[name])) then
|
||
|
|
if(old != new) then
|
||
|
|
_varhandlers[name](self, old, new)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:OnStartShooting() end
|
||
|
|
function ENT:OnStopShooting() end
|
||
|
|
function ENT:DoShootThink() return false end
|
||
|
|
function ENT:OnStartAttack() end
|
||
|
|
function ENT:OnStopAttack() end
|
||
|
|
function ENT:OnDeactivateGun() end
|
||
|
|
function ENT:OnActivateGun() end
|
||
|
|
|
||
|
|
function ENT:BakuRegisterMannable()
|
||
|
|
__BakuRegisteredMannableClasses = __BakuRegisteredMannableClasses or {}
|
||
|
|
__BakuRegisteredMannableClasses[self:GetClass()] = true
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:BakuManned(bool)
|
||
|
|
if(bool) then
|
||
|
|
__BakuManTableAR3[self._User:EntIndex()] = self
|
||
|
|
else
|
||
|
|
__BakuManTableAR3[self._User:EntIndex()] = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:BakuIsManned(user)
|
||
|
|
return IsValid(__BakuManTableAR3[user:EntIndex()])
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:BakuRemoveFromVehicle()
|
||
|
|
__BakuVehicleTableAR3[self._Vehicle:EntIndex()] = nil
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:InitAIControll()
|
||
|
|
self:AR3Deactivate()
|
||
|
|
|
||
|
|
self._AIControlled = true
|
||
|
|
self._User = NULL
|
||
|
|
self._Active = false
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:DoAIThink()
|
||
|
|
if(!IsValid(self._AIEnemy)) then
|
||
|
|
local enemy = player.GetAll()[1]
|
||
|
|
|
||
|
|
self._AIEnemy = enemy
|
||
|
|
|
||
|
|
if(IsValid(enemy) && enemy:Alive() && !self._Active) then
|
||
|
|
self:AR3Activate()
|
||
|
|
end
|
||
|
|
else
|
||
|
|
local tr = util.TraceLine({
|
||
|
|
start = self:GetAttachment(1).Pos,
|
||
|
|
endpos = self._AIEnemy:GetPos() + self._AIEnemy:OBBCenter(),
|
||
|
|
filter = self
|
||
|
|
})
|
||
|
|
|
||
|
|
if(tr.Entity == self._AIEnemy) then
|
||
|
|
self._AIAimPoint = tr.HitPos
|
||
|
|
self._AIShooting = true
|
||
|
|
end
|
||
|
|
|
||
|
|
if(IsValid(self._AIEnemy) || !self._AIEnemy:Alive()) then
|
||
|
|
//self:AR3Deactivate()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Initialize()
|
||
|
|
self._User = NULL
|
||
|
|
self._UserPrevWeapon = NULL
|
||
|
|
self._Active = false
|
||
|
|
self._DriveMode = false
|
||
|
|
self._Vehicle = NULL
|
||
|
|
self.ShootDelay = 0.075
|
||
|
|
self._Ammo = -1
|
||
|
|
|
||
|
|
self._OldAim = Vector(0, 0, 0)
|
||
|
|
|
||
|
|
self._ShootTimer = 0
|
||
|
|
self._UseTimer = 0
|
||
|
|
self._SequenceTimer = 0
|
||
|
|
self._IsShooting = false
|
||
|
|
self._HideGunModel = false
|
||
|
|
self._Automatic = true
|
||
|
|
self._DoNetworking = true
|
||
|
|
self._PitchOffset = 0
|
||
|
|
|
||
|
|
//AI
|
||
|
|
self._AIControlled = false
|
||
|
|
self._AIShooting = false
|
||
|
|
self._AIAimPoint = Vector(0, 0, 0)
|
||
|
|
self._AIEnemy = NULL
|
||
|
|
|
||
|
|
self:DoInit()
|
||
|
|
|
||
|
|
if(self._HideGunModel) then
|
||
|
|
self:SetModel("models/props_combine/bunker_gun01_nogun.mdl")
|
||
|
|
else
|
||
|
|
self:SetModel("models/props_combine/bunker_gun01.mdl")
|
||
|
|
end
|
||
|
|
|
||
|
|
self:PhysicsInitBox(-Vector(8,8,0), Vector(8,8,8))
|
||
|
|
|
||
|
|
local phys = self:GetPhysicsObject()
|
||
|
|
if(IsValid(phys)) then
|
||
|
|
phys:Wake()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetUseType(USE_TOGGLE)
|
||
|
|
end
|
||
|
|
|
||
|
|
local usetime = 0.5
|
||
|
|
|
||
|
|
function ENT:AR3Activate()
|
||
|
|
self:ResetSequence(1)
|
||
|
|
self._SequenceTimer = CurTime() + 0.5
|
||
|
|
|
||
|
|
if(IsValid(self._User) && !self._AIControlled) then
|
||
|
|
if(!self._DriveMode) then
|
||
|
|
self._UserPrevWeapon = self._User:GetActiveWeapon()
|
||
|
|
self._User:SetActiveWeapon(NULL)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:BakuManned(true)
|
||
|
|
|
||
|
|
self:EmitSound("weapons/shotgun/shotgun_cock.wav")
|
||
|
|
end
|
||
|
|
self._Active = true
|
||
|
|
|
||
|
|
self._OldAim = self:GetForward()
|
||
|
|
self:OnActivateGun()
|
||
|
|
|
||
|
|
if(self._DoNetworking) then
|
||
|
|
self:SetNWBool("_active", true)
|
||
|
|
self:SetNWBool("_drive", self._DriveMode)
|
||
|
|
self:SetNWEntity("_user", self._User)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:AR3Deactivate()
|
||
|
|
self:ResetSequence(3)
|
||
|
|
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||
|
|
|
||
|
|
if(self._IsShooting) then
|
||
|
|
self:OnStopShooting()
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self._IsKeyDown) then
|
||
|
|
self:OnStopAttack()
|
||
|
|
end
|
||
|
|
|
||
|
|
self._IsShooting = false
|
||
|
|
self._IsKeyDown = false
|
||
|
|
|
||
|
|
if(IsValid(self._User) && !self._AIControlled) then
|
||
|
|
if(!self._DriveMode && IsValid(self._UserPrevWeapon)) then
|
||
|
|
self._User:SelectWeapon(self._UserPrevWeapon:GetClass() or "weapon_crowbar")
|
||
|
|
end
|
||
|
|
|
||
|
|
self:BakuManned(false)
|
||
|
|
self._Active = false
|
||
|
|
|
||
|
|
self:EmitSound("weapons/shotgun/shotgun_cock.wav")
|
||
|
|
self:OnDeactivateGun()
|
||
|
|
end
|
||
|
|
|
||
|
|
self._User = NULL
|
||
|
|
|
||
|
|
if(self._DoNetworking) then
|
||
|
|
self:SetNWBool("_active", false)
|
||
|
|
self:SetNWBool("_drive", self._DriveMode)
|
||
|
|
self:SetNWEntity("_user", self._User)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Use(act, caller, _type, _val)
|
||
|
|
if(self._UseTimer > CurTime() || act:EyePos():DistToSqr(self:GetPos()) > 64 * 64 || self._AIControlled) then return end
|
||
|
|
|
||
|
|
if(self._DriveMode) then
|
||
|
|
if(IsValid(self._Vehicle) && IsValid(JBUFindTheEntInConstraints(self._Vehicle, "Weld", self:GetClass()))) then return
|
||
|
|
else
|
||
|
|
self:BakuRemoveFromVehicle()
|
||
|
|
self._Vehicle = NULL
|
||
|
|
self._DriveMode = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if(!IsValid(self._User) && !self:BakuIsManned(act)) then
|
||
|
|
self._User = act
|
||
|
|
|
||
|
|
self:AR3Activate()
|
||
|
|
elseif(self._User == act) then
|
||
|
|
self:AR3Deactivate()
|
||
|
|
end
|
||
|
|
|
||
|
|
self._UseTimer = CurTime() + usetime
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:OnRemove()
|
||
|
|
self:AR3Deactivate()
|
||
|
|
self:DoRemove()
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:DoShoot(dest)
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:IsGunShooting()
|
||
|
|
return (!self._AIControlled && IsValid(self._User) && self._User:KeyDown(IN_ATTACK)) || (self._AIControlled && self._AIShooting)
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Think()
|
||
|
|
if(self._Active && (!self._AIControlled && IsValid(self._User))) then
|
||
|
|
local aimpoint
|
||
|
|
|
||
|
|
if(self._AIControlled) then
|
||
|
|
aimpoint = self._AIAimPoint
|
||
|
|
else
|
||
|
|
if(IsValid(self._User)) then
|
||
|
|
local ply = self._User
|
||
|
|
|
||
|
|
if(ply:EyePos():DistToSqr(self:GetPos()) > 64 * 64 && !self._DriveMode || !ply:Alive()) then
|
||
|
|
self:AR3Deactivate()
|
||
|
|
end
|
||
|
|
|
||
|
|
local _filter_ = {self, ply}
|
||
|
|
|
||
|
|
if(ply:InVehicle()) then
|
||
|
|
table.insert(_filter_, ply:GetVehicle())
|
||
|
|
end
|
||
|
|
|
||
|
|
local tr = util.TraceLine({
|
||
|
|
start = ply:EyePos(),
|
||
|
|
endpos = ply:EyePos() + ply:GetAimVector() * 65535,
|
||
|
|
filter = _filter_ or self
|
||
|
|
})
|
||
|
|
|
||
|
|
aimpoint = tr.HitPos
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local transposed1 = JBUmatTranspose3x3(self:GetWorldTransformMatrix())
|
||
|
|
local look = (aimpoint - self:GetBonePosition(4))
|
||
|
|
local __dist = look:LengthSqr()
|
||
|
|
look:Normalize()
|
||
|
|
local mydestlook = JBUApproachVector(self._OldAim, look, 2 * FrameTime())
|
||
|
|
|
||
|
|
self._OldAim = mydestlook
|
||
|
|
local transformed = transposed1 * look
|
||
|
|
local relang = transformed:Angle()
|
||
|
|
|
||
|
|
if(relang.yaw > 180) then
|
||
|
|
relang.yaw = relang.yaw - 360
|
||
|
|
end
|
||
|
|
|
||
|
|
if(relang.pitch > 180) then
|
||
|
|
relang.pitch = relang.pitch - 360
|
||
|
|
end
|
||
|
|
|
||
|
|
if(__dist > 2000) then
|
||
|
|
self:ClearPoseParameters()
|
||
|
|
self:SetPoseParameter("aim_yaw", relang.yaw)
|
||
|
|
self:SetPoseParameter("aim_pitch", relang.pitch + self._PitchOffset)
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self:IsGunShooting()) then
|
||
|
|
if(!self._IsKeyDown) then
|
||
|
|
self:OnStartAttack()
|
||
|
|
self._IsKeyDown = true
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self._ShootTimer < CurTime() && (self._Automatic || !self._IsShooting)) then
|
||
|
|
if(self._Ammo > 0 || self._Ammo < 0) then
|
||
|
|
if(!self._IsShooting) then
|
||
|
|
self._IsShooting = true
|
||
|
|
self:OnStartShooting()
|
||
|
|
end
|
||
|
|
local dest = mydestlook
|
||
|
|
|
||
|
|
if(math.abs(relang.yaw) > 60 || relang.pitch < -35 || relang.pitch > 60) then
|
||
|
|
dest = self:GetAttachment(1).Ang:Forward()
|
||
|
|
end
|
||
|
|
|
||
|
|
if(!self:DoShootThink()) then
|
||
|
|
self:DoShoot(dest)
|
||
|
|
self._ShootTimer = CurTime() + self.ShootDelay
|
||
|
|
|
||
|
|
self:ResetSequence(2)
|
||
|
|
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||
|
|
|
||
|
|
if(self._Ammo > 0) then
|
||
|
|
self._Ammo = self._Ammo - 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
elseif(self._IsShooting) then
|
||
|
|
self:OnStopShooting()
|
||
|
|
self._IsShooting = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
if(self._IsShooting) then
|
||
|
|
self:OnStopShooting()
|
||
|
|
self._IsShooting = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self._IsKeyDown) then
|
||
|
|
self._IsKeyDown = false
|
||
|
|
self:OnStopAttack()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self._AIControlled) then
|
||
|
|
self:DoAIThink()
|
||
|
|
end
|
||
|
|
|
||
|
|
if(self._SequenceTimer < CurTime() && self._Active) then
|
||
|
|
self:ResetSequence(0)
|
||
|
|
self._SequenceTimer = CurTime() + self:SequenceDuration()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:NextThink(CurTime())
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
else
|
||
|
|
function ENT.BaseDupeFunction(ply, data)
|
||
|
|
data._User = NULL
|
||
|
|
data._Active = false
|
||
|
|
|
||
|
|
scripted_ents.Get(data.Class).DupeFunction(ply, data)
|
||
|
|
|
||
|
|
return duplicator.GenericDuplicatorFunction(ply, data)
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:DoNotification()
|
||
|
|
if(!IsValid(self._User) or self._User != LocalPlayer()) then return end
|
||
|
|
|
||
|
|
local cookiename = self:GetClass() .. "_notifycookie"
|
||
|
|
if(self._Notification && cookie.GetNumber(cookiename, 0) < os.time()) then
|
||
|
|
cookie.Set(cookiename, tostring(os.time() + 7200))
|
||
|
|
|
||
|
|
local notif = {}
|
||
|
|
if(isstring(self._Notification)) then
|
||
|
|
notif[1] = self._Notification
|
||
|
|
elseif(istable(self._Notification)) then
|
||
|
|
notif = self._Notification
|
||
|
|
end
|
||
|
|
|
||
|
|
local __i = 0
|
||
|
|
for k, v in pairs(notif) do
|
||
|
|
timer.Simple(__i * 0.6, function()
|
||
|
|
notification.AddLegacy( v, NOTIFY_HINT, 5 )
|
||
|
|
surface.PlaySound( "buttons/button15.wav" )
|
||
|
|
end)
|
||
|
|
|
||
|
|
__i = __i + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:SetupCustomModel(mdl, bone, rendergroup)
|
||
|
|
if(IsValid(self._CustomGunModel)) then
|
||
|
|
self._CustomGunModel:SetModel(mdl)
|
||
|
|
else
|
||
|
|
rendergroup = rendergroup or RENDERGROUP_OPAQUE
|
||
|
|
self._CustomGunModel = ClientsideModel(mdl, rendergroup)
|
||
|
|
self._CustomGunModel:SetNoDraw(true)
|
||
|
|
end
|
||
|
|
self._CModelBone = bone or self._CModelBone or 0
|
||
|
|
|
||
|
|
return self._CustomGunModel
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:OnDeactivateGun() end
|
||
|
|
function ENT:OnActivateGun() end
|
||
|
|
function ENT:DoDraw() end
|
||
|
|
function ENT:DoThink() end
|
||
|
|
|
||
|
|
function ENT:Initialize()
|
||
|
|
local mins, maxs = self:GetModelBounds()
|
||
|
|
self:SetRenderBounds(mins, maxs, Vector(1, 1, 1) * 30)
|
||
|
|
|
||
|
|
self._CModelBone = 0
|
||
|
|
self._Active = false
|
||
|
|
self._User = NULL
|
||
|
|
self._DriveMode = false
|
||
|
|
|
||
|
|
self:DoInit()
|
||
|
|
|
||
|
|
if(IsValid(self._CustomGunModel)) then
|
||
|
|
self._GunModelMatrix = self._GunModelMatrix or Matrix()
|
||
|
|
|
||
|
|
self._CustomGunModel:SetNoDraw(true)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Think()
|
||
|
|
if(self._Active && !self:GetNWBool("_active")) then
|
||
|
|
self:OnDeactivateGun()
|
||
|
|
self._Active = false
|
||
|
|
|
||
|
|
if(self._DriveMode && LocalPlayer() == self._User) then
|
||
|
|
local mins, maxs = self:GetModelBounds()
|
||
|
|
self:SetRenderBounds(mins, maxs, Vector(1, 1, 1) * 30)
|
||
|
|
end
|
||
|
|
|
||
|
|
self._User = NULL
|
||
|
|
self._DriveMode = false
|
||
|
|
elseif(!self._Active && self:GetNWBool("_active")) then
|
||
|
|
self._User = self:GetNWEntity("_user")
|
||
|
|
self._DriveMode = self:GetNWBool("_drive")
|
||
|
|
self._Active = true
|
||
|
|
self:OnActivateGun()
|
||
|
|
self:DoNotification()
|
||
|
|
|
||
|
|
if(self._DriveMode && LocalPlayer() == self._User) then
|
||
|
|
local _x_y_z = Vector(65535, 65535, 65535)
|
||
|
|
self:SetRenderBounds(-_x_y_z, _x_y_z)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:DoThink()
|
||
|
|
end
|
||
|
|
|
||
|
|
local chair = Material("sprites/hud/v_crosshair1")
|
||
|
|
local flashlight = Material("sprites/glow03")
|
||
|
|
local glow = Material("sprites/glow_test02")
|
||
|
|
|
||
|
|
function ENT:DrawCustomGunModel()
|
||
|
|
self._CustomGunModel:SetupBones()
|
||
|
|
|
||
|
|
local mat2 = self:GetBoneMatrix(4) * self._GunModelMatrix
|
||
|
|
|
||
|
|
self._CustomGunModel:SetPos(self:GetPos())
|
||
|
|
self._CustomGunModel:SetBoneMatrix(self._CModelBone, mat2)
|
||
|
|
self._CustomGunModel:DrawModel()
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Draw()
|
||
|
|
self:DrawModel()
|
||
|
|
self:DoDraw()
|
||
|
|
|
||
|
|
if(IsValid(self._CustomGunModel)) then
|
||
|
|
self:DrawCustomGunModel()
|
||
|
|
end
|
||
|
|
|
||
|
|
local ply = self._User
|
||
|
|
|
||
|
|
if(self._DriveMode && ply == LocalPlayer()) then
|
||
|
|
render.SetMaterial(chair)
|
||
|
|
render.DrawSprite(ply:EyePos() + ply:GetAimVector() * 200, 8, 8, Color(255,255,0,255))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:OnRemove()
|
||
|
|
if(IsValid(self._CustomGunModel)) then
|
||
|
|
self._CustomGunModel:Remove()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:OnDeactivateGun()
|
||
|
|
self:DoRemove()
|
||
|
|
end
|
||
|
|
end
|