Hello,
i try to “develop” my first Traitor Item for TTT. First of all i have to say that most parts of the Code i copied from persistens codes. It is not my purpose to steal codes from another developers here, but i use it to learn about the programming language and will use this for my own test purpose, not to publish it on any platform (e.g. steam workshop or anyother). If this breaks the rules, feel free to delete the Thread/Post.
I try to develop a Snark Spawner as Traitor Item, which will attacks the Innocents. If you dont know what Snarks are, check the Half-Life 1 Enemylist via Google to check that.
When i start my Server with my Addon i get this error:
[ERROR] lua/entities/npc_vj_bmsno_snark/shared.lua:3: attempt to index global ‘SWEP’ (a nil value)
- unknown - lua/entities/npc_vj_bmsno_snark/shared.lua:3
- include - [C]:-1
3. unknown - lua/entities/npc_vj_bmsno_snark/init.lua:2
The content from my shared.lua is following (path is this on my server /home/steam/steamcmd/gm/garrysmod/lua/entities/npc_vj_bmsno_snark/shared.lua):
resource.AddFile("materials/VGUI/entities/npc_vj_bmsno_snark.vmt")
SWEP.Base = "weapon_tttbasegrenade"
SWEP.Kind = WEAPON_EQUIP2
SWEP.WeaponID = AMMO_MOLOTOV
SWEP.HoldType = "grenade"
SWEP.CanBuy = { ROLE_TRAITOR }
SWEP.InLoadoutFor = nil
SWEP.LimitedStock = true
SWEP.AllowDrop = true
SWEP.IsSilent = false
SWEP.NoSights = true
SWEP.ViewModel = "models/weapons/v_eq_flashbang.mdl"
SWEP.WorldModel = "models/props_lab/clipboard.mdl"
SWEP.Weight = 5
SWEP.AutoSpawnable = false
-- really the only difference between grenade weapons: the model and the thrown
-- ent.
local mymodel = ""
if CLIENT then
-- Path to the icon material
SWEP.PrintName = "Snark Spawner"
SWEP.Slot = 7
if file.Exists("materials/VGUI/entities/npc_vj_bmsno_snark.png", "GAME") then
SWEP.Icon = "VGUI/entities/npc_vj_bmsno_snark"
else
SWEP.Icon = "VGUI/entities/icon_nades"
end
-- Text shown in the equip menu
SWEP.EquipMenuData = {
type = "Weapon",
desc = "Spawn Snark to replace props."
};
function SWEP:DrawWorldModel()
--self:DrawModel()
local ply = self.Owner
local pos = self.Weapon:GetPos()
local ang = self.Weapon:GetAngles()
if ply:IsValid() then
local bone = ply:LookupBone("ValveBiped.Bip01_R_Hand")
if bone then
pos,ang = ply:GetBonePosition(bone)
end
else
self.Weapon:DrawModel() --Draw the actual model when not held.
return
end
if self.ModelEntity:IsValid() == false then
self.ModelEntity = ClientsideModel(self.WorldModel)
self.ModelEntity:SetNoDraw(true)
end
self.ModelEntity:SetModelScale(1,0)
self.ModelEntity:SetPos(pos)
self.ModelEntity:SetAngles(ang+Angle(0,0,0))
self.ModelEntity:DrawModel()
end
function SWEP:ViewModelDrawn()
local ply = self.Owner
if ply:IsValid() and ply == LocalPlayer() then
local vmodel = ply:GetViewModel()
local idParent = vmodel:LookupBone("v_weapon.Flashbang_Parent")
local idBase = vmodel:LookupBone("v_weapon")
if not vmodel:IsValid() or not idParent or not idBase then return end --Ensure the model and bones are valid.
local pos, ang = vmodel:GetBonePosition(idParent)
local pos1, ang1 = vmodel:GetBonePosition(idBase) --Rotations were screwy with the parent's angle; use the models baseinstead.
if self.ModelEntity:IsValid() == false then
self.ModelEntity = ClientsideModel(self.WorldModel)
self.ModelEntity:SetNoDraw(true)
end
self.ModelEntity:SetModelScale(0.5,0)
self.ModelEntity:SetPos(pos-ang1:Forward()*1.25-ang1:Up()*0.5+2.3*ang1:Right())
self.ModelEntity:SetAngles(ang1+Angle(90,0,90))
self.ModelEntity:DrawModel()
end
end
end
function SWEP:GetGrenadeName()
end
--Taken from base grenade
function SWEP:Initialize()
if self.SetWeaponHoldType then
self:SetWeaponHoldType(self.HoldNormal)
end
self:SetDeploySpeed(self.DeploySpeed)
self:SetDetTime(0)
self:SetThrowTime(0)
self:SetPin(false)
self.was_thrown = false
if CLIENT then
self.ModelEntity = ClientsideModel(self.WorldModel)
self.ModelEntity:SetNoDraw(true)
end
end
function SWEP:OnRemove()
if CLIENT and IsValid(self.Owner) and self.Owner == LocalPlayer() and self.Owner:Alive() then
RunConsoleCommand("use", "weapon_ttt_unarmed")
end
if CLIENT then
self.ModelEntity:Remove()
end
end
function SWEP:PrimaryAttack()
mymodel = table.Count(ents.FindByClass( "prop_*" ))
local oneman = 1
local maxmodel = 60
if mymodel > 60 then
maxmodel = 60
else
maxmodel = mymodel
end
if SERVER then
if math.random( 1, maxmodel ) > oneman then
for i=1,math.random( 1, maxmodel ) do
local ent = ents.Create("init") -- This creates our npc entity
ent:Spawn()
end
end
end
for k, v in pairs( player.GetAll() ) do
if v:GetRole() == ROLE_TRAITOR then
v:PrintMessage( HUD_PRINTTALK, maxmodel .. " Snark Spawned" )
end
end
self:Remove()
end
The content from my init.lua is following (path is this on my server /home/steam/steamcmd/gm/garrysmod/lua/entities/npc_vj_bmsno_snark/init.lua):
AddCSLuaFile("shared.lua")
include('shared.lua')
ENT.Model = {"models/VJ_BLACKMESA/snark.mdl"} -- The game will pick a random model from the table when the SNPC is spawned | Add as many as you want
ENT.StartHealth = GetConVarNumber("vj_bms_snark_h")
ENT.HullType = HULL_TINY
---------------------------------------------------------------------------------------------------------------------------------------------
ENT.HasMeleeAttack = true -- Should the SNPC have a melee attack?
ENT.AnimTbl_MeleeAttack = {} -- Melee Attack Animations
ENT.MeleeAttackDistance = 50 -- How close does it have to be until it attacks?
ENT.MeleeAttackDamageDistance = 50 -- How far does the damage go?
ENT.TimeUntilMeleeAttackDamage = 0.1 -- This counted in seconds | This calculates the time until it hits something
ENT.NextAnyAttackTime_Melee = 0.4 -- How much time until it can use any attack again? | Counted in Seconds
ENT.MeleeAttackDamage = GetConVarNumber("vj_bms_snark_bite_d")
ENT.HasLeapAttack = true -- Should the SNPC have a leap attack?
ENT.AnimTbl_LeapAttack = {ACT_GLIDE} -- Melee Attack Animations
ENT.LeapDistance = 200 -- The distance of the leap, for example if it is set to 500, when the SNPC is 500 Unit away, it will jump
ENT.LeapToMeleeDistance = 0 -- How close does it have to be until it uses melee?
ENT.TimeUntilLeapAttackDamage = 0.4 -- How much time until it runs the leap damage code?
ENT.NextLeapAttackTime = 0.4 -- How much time until it can use a leap attack?
ENT.NextAnyAttackTime_Leap = 0.4 -- How much time until it can use any attack again? | Counted in Seconds
ENT.LeapAttackExtraTimers = {0.2,0.6} -- Extra leap attack timers | it will run the damage code after the given amount of seconds
ENT.LeapAttackVelocityForward = 100 -- How much forward force should it apply?
ENT.LeapAttackVelocityUp = 180 -- How much upward force should it apply?
ENT.LeapAttackDamage = GetConVarNumber("vj_bms_snark_jumpbite_d")
ENT.LeapAttackDamageDistance = 100 -- How far does the damage go?
ENT.HasDeathRagdoll = false -- If set to false, it will not spawn the regular ragdoll of the SNPC
ENT.PushProps = false -- Should it push props when trying to move?
ENT.EntitiesToNoCollide = {"npc_vj_bmsno_snark"}
ENT.FindEnemy_UseSphere = true -- Should the SNPC be able to see all around him? (360) | Objects and walls can still block its sight!
-- ====== Sound File Paths ====== --
-- Leave blank if you don't want any sounds to play
ENT.SoundTbl_Idle = {"vj_bms_snark/hunt1.wav","vj_bms_snark/hunt2.wav","vj_bms_snark/hunt3.wav","vj_bms_snark/hunt4.wav"}
ENT.SoundTbl_Alert = {"vj_bms_snark/deploy1.wav","vj_bms_snark/deploy2.wav","vj_bms_snark/deploy3.wav"}
ENT.SoundTbl_MeleeAttack = {"vj_bms_snark/bite01.wav","vj_bms_snark/bite02.wav","vj_bms_snark/bite03.wav","vj_bms_snark/bite04.wav","vj_bms_snark/bite05.wav"}
ENT.SoundTbl_MeleeAttackMiss = {"vj_bms_snark/hunt1.wav","vj_bms_snark/hunt2.wav","vj_bms_snark/hunt3.wav","vj_bms_snark/hunt4.wav"}
ENT.SoundTbl_LeapAttackDamage = {"vj_bms_snark/bite01.wav","vj_bms_snark/bite02.wav","vj_bms_snark/bite03.wav","vj_bms_snark/bite04.wav","vj_bms_snark/bite05.wav"}
ENT.SoundTbl_LeapAttackDamageMiss = {"vj_bms_snark/hunt1.wav","vj_bms_snark/hunt2.wav","vj_bms_snark/hunt3.wav","vj_bms_snark/hunt4.wav"}
ENT.SoundTbl_Pain = {"vj_bms_snark/die01.wav","vj_bms_snark/die02.wav","vj_bms_snark/die03.wav","vj_bms_snark/die04.wav"}
ENT.SoundTbl_Death = {"vj_bms_snark/blast1.wav"}
-- Custom
ENT.Snark_Explodes = true
ENT.Snark_NextJumpWalkTime1 = 0.35
ENT.Snark_NextJumpWalkTime2 = 0.8
ENT.Snark_NextJumpWalkT = 0
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnInitialize()
self:SetCollisionBounds(Vector(5, 5, 10), Vector(-5, -5, 0))
//self:PhysicsInitBox(self:GetModelBounds())
//self.MeleeAttackDamage = math.random(3,5)
//self.LeapAttackDamage = math.random(3,5)
self:CapabilitiesAdd(bit.bor(CAP_MOVE_CLIMB))
self.Snark_EnergyTime = CurTime() + GetConVarNumber("vj_bms_snarkexplodetime")
if GetConVarNumber("vj_bms_snarkexplode") == 0 then self.Snark_Explodes = false end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnThink_AIEnabled()
//PrintMessage(HUD_PRINTTALK,"CURTIME: "..CurTime())
//PrintMessage(HUD_PRINTTALK,self.Snark_EnergyTime)
if self:GetEnemy() != nil && self.VJ_IsBeingControlled == false then
if self:IsOnGround() && self:Visible(self:GetEnemy()) && self:GetPos():Distance(self:GetEnemy():GetPos()) > self.LeapDistance + 10 && CurTime() > self.Snark_NextJumpWalkT then
self:VJ_ACT_PLAYACTIVITY(ACT_GLIDE,false,0.7,true)
self:SetGroundEntity(NULL)
self:SetLocalVelocity((self:GetEnemy():GetPos() -self:GetPos()):GetNormal() *500 +self:GetUp() *math.Rand(165,200) +self:GetForward() *math.Rand(180,220))
self.Snark_NextJumpWalkT = CurTime() + math.Rand(self.Snark_NextJumpWalkTime1,self.Snark_NextJumpWalkTime2)
end
end
if self.Snark_Explodes == true && self.Snark_EnergyTime < CurTime() then
self:DeathSoundCode()
self:CustomOnKilled(dmginfo,hitgroup)
self:Remove()
end
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnMeleeAttack_AfterChecks(TheHitEntity)
//PrintMessage(HUD_PRINTTALK,"MELEE")
self.Snark_EnergyTime = self.Snark_EnergyTime + 0.5
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnLeapAttack_AfterChecks(TheHitEntity)
self.Snark_EnergyTime = self.Snark_EnergyTime + 0.5
end
---------------------------------------------------------------------------------------------------------------------------------------------
function ENT:CustomOnKilled(dmginfo,hitgroup)
if self.HasGibDeathParticles == true then
local bloodeffect = EffectData()
bloodeffect:SetOrigin(self:GetPos() +self:OBBCenter())
bloodeffect:SetColor(VJ_Color2Byte(Color(255,221,35)))
bloodeffect:SetScale(40)
util.Effect("VJ_Blood1",bloodeffect)
local bloodspray = EffectData()
bloodspray:SetOrigin(self:GetPos() +self:OBBCenter())
bloodspray:SetScale(6)
bloodspray:SetFlags(3)
bloodspray:SetColor(1)
util.Effect("bloodspray",bloodspray)
util.Effect("bloodspray",bloodspray)
local effectdata = EffectData()
effectdata:SetOrigin(self:GetPos() +self:OBBCenter())
effectdata:SetScale(0.4)
util.Effect("StriderBlood",effectdata)
util.Effect("StriderBlood",effectdata)
end
end