First Scripted Weapon
![]() | Article about SWEP. |
![]() | Dim1xs |
![]() | September 28th 2023 |
This article will learn you, how to create code your first Scirpted Weapon - SWEP
Scripted Weapons
Better known as a SWep (or SWEP in some cases) a scripted weapon is a weapon that has an underlying script controlling its operation. In this tutorial, we will be making a SWep with fire bullets function.
The Basic Layout
First of all, you need a program, that can open and edit Lua format files.
Go to the directory (folder): '.. /lua/weapons/'
Now create a new folder, with a simple name (without spaces) for your weapon. (for example: weapon_gun)
I recommend naming the folder so that there is a prefix at the beginning: 'weapon_'
I advise you to do this, because the game may have the same prefixes, and the game may break because of this.
Go to the directory (folder): '.. /lua/weapons/'
Now create a new folder, with a simple name (without spaces) for your weapon. (for example: weapon_gun)
I recommend naming the folder so that there is a prefix at the beginning: 'weapon_'
I advise you to do this, because the game may have the same prefixes, and the game may break because of this.
Files
In folder that you created, you need to create 3 files:
🔵init.lua
🔵cl_init.lua
🔵shared.lua
init.lua is run Serverside functions.
cl_init.lua is run Clientside functions.
shared.lua is run in both environments (server/clientside).
Now, for perfect work you have to open cl_init.lua and put here basic code:
Now same for init.lua:
🔵init.lua
🔵cl_init.lua
🔵shared.lua
init.lua is run Serverside functions.
cl_init.lua is run Clientside functions.
shared.lua is run in both environments (server/clientside).
Now, for perfect work you have to open cl_init.lua and put here basic code:
include( "shared.lua" ) --Must be here, for normal client initialize without errors. function SWEP:DrawLargeWeaponBox( bSelected, xpos, ypos, boxWide, boxTall, selectedColor, alpha, number ) --Must be here so that it does not give an error. end function SWEP:DrawModel( flags ) end function SWEP:MuzzleFlash( pos1, angles, type, firstPerson ) end
Now same for init.lua:
include( "shared.lua" ) --Must be here, for normal server initialize without errors. function SWEP:CapabilitiesGet() end
SWEP Functions
You have to know, how classes in lua are working, for simple: if function has self: in the string it means self is the base class of the script.
if you will dont have SWEP: or ENT: etc in your function name, self: will not work! Because SWEP: is like a structure.
Okay so, you must put a basic functions like Name, Viewmodel, Worldmodel of weapon, so for that you can use same functions like in GMOD:
if you will dont have SWEP: or ENT: etc in your function name, self: will not work! Because SWEP: is like a structure.
Okay so, you must put a basic functions like Name, Viewmodel, Worldmodel of weapon, so for that you can use same functions like in GMOD:
SWEP.Name = "Base Weapon" --in SpawnMenu Name SWEP.PrintName = "#HL2_357Handgun" SWEP.ViewModel = "models/weapons/v_357.mdl" SWEP.WorldModel = "models/weapons/w_357.mdl" SWEP.HoldType = "python" --dont working SWEP.Slot = 1 SWEP.SlotPos = 1 SWEP.Weight = 7 SWEP.item_flags = 0 SWEP.AutoSwitchTo = 1 SWEP.AutoSwitchFrom = 1 SWEP.BuiltRightHanded = 0 SWEP.AllowFlipping = 0 --actually does the same like ViewModelFlip in gmod. SWEP.MeleeWeapon = 0 --idk what it does. SWEP.Spawnable = true SWEP.AdminOnly = false
Firearm Settings
Each weapon must have its parameters configured (cartridges, magazine stock, initial ammunition, type of cartridges)
Fortunately, in this lua, the ammo def functions work the same way as in gmod, which means that they are tables, and I can show you 2 ways for setting up ammo.
First way, is making in like in default gmod swep:
Fortunately, in this lua, the ammo def functions work the same way as in gmod, which means that they are tables, and I can show you 2 ways for setting up ammo.
First way, is making in like in default gmod swep:
--This determins how big each clip/magazine for the gun is. You can --set it to -1 to disable the ammo system, meaning primary ammo will --not be displayed and will not be affected. SWEP.Primary.ClipSize = 126 --This sets the number of rounds in the clip when you first get the gun. Again it can be set to -1. SWEP.Primary.DefaultClip = 126 --Obvious. Determines whether the primary fire is automatic. This should be true/false SWEP.Primary.Automatic = false --Sets the ammunition type the gun uses, see below for a list of types. SWEP.Primary.Ammo = "357 SWEP.Secondary.ClipSize = -1 SWEP.Secondary.DefaultClip = -1 SWEP.Secondary.Automatic = false SWEP.Secondary.Ammo = "None"And here is the second way:
SWEP.Primary = { ClipSize=126, DefaultClip=126, Automatic = false, Ammo = "357", } SWEP.Secondary = { ClipSize=-1, DefaultClip=-1, Automatic = false, Ammo = "none", }I like the second way better, it looks clearer to me.
Ammo list:
AR2 - Ammunition of the AR2/Pulse Rifle AlyxGun - (name in-game "5.7mm Ammo") Pistol - Ammunition of the 9MM Pistol SMG1 - Ammunition of the SMG/MP7 357 - Ammunition of the .357 Magnum XBowBolt - Ammunition of the Crossbow Buckshot - Ammunition of the Shotgun RPG_Round - Ammunition of the RPG/Rocket Launcher SMG1_Grenade - Ammunition for the SMG/MP7 grenade launcher (secondary fire)And the last one is Damage of SWEP:
SWEP.damage = 15
Player Animations
Now, i will show how to add a animations for the player:
below this is a example with AR2 animations (aka rifle), if you want to change them,
look for ACT Enums on gmod wiki, or wait untill they will be done in this wiki.
SWEP.m_acttable = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_AR2, true }, { ACT_RELOAD, ACT_RELOAD_SMG1, true }, { ACT_IDLE, ACT_IDLE_SMG1, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SMG1, true }, { ACT_WALK, ACT_WALK_RifLE, true }, { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false }, { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false }, { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_AR2, false }, { ACT_MP_STAND_IDLE, ACT_HL2MP_IDLE_AR2, false }, { ACT_MP_CROUCH_IDLE, ACT_HL2MP_IDLE_CROUCH_AR2, false }, { ACT_MP_RUN, ACT_HL2MP_RUN_AR2, false }, { ACT_MP_CROUCHWALK, ACT_HL2MP_WALK_CROUCH_AR2, false }, { ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, { ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, { ACT_MP_RELOAD_STAND, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_MP_RELOAD_CROUCH, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, };Sadly HoldType from gmod is still not realised, so we have to use a act table like in C++,
below this is a example with AR2 animations (aka rifle), if you want to change them,
look for ACT Enums on gmod wiki, or wait untill they will be done in this wiki.
Sounds
Sadly, you can't do the shoot sound with the same way like in gmod, and you have to use SWEP.SoundData table:
That's probably same thing like in game weapon scripts (.txt)
That's probably same thing like in game weapon scripts (.txt)
SWEP.SoundData =
{
empty = "Weapon_Pistol.Empty",
single_shot = "weapons/sound.wav" --any sound here
}
Remember! You don't need to write 'sound/' in path! It puts it automatically!Functions
Now you gonna code!
Starting from basics, SWEP:Initialize is used for defining values/bools and also is used for default weapon functions:
But of course i will give you a example, i'm not sure you could understand anything:
Starting from basics, SWEP:Initialize is used for defining values/bools and also is used for default weapon functions:
function SWEP:Initialize() self.m_bReloadsSingly = false; self.m_bFiresUnderwater = false; endBelow you can see 2 basic functions, they do the same thing that is written on them.
But of course i will give you a example, i'm not sure you could understand anything:
function SWEP:Initialize() self.IsBool = true -- it's gonna be true by default IsBool = true --the same but not in swep global. self.RandVal = 5 -- it's gonna equals to 5 by default RandVal = 5 -- the same but not in swep global. endNext we will do the primary attack in our script!
function SWEP:PrimaryAttack() --code endEvery time you do the SWEP, don't forget to idenify the entity of the player who uses the weapon!
function SWEP:PrimaryAttack() local pPlayer = self:GetOwner() --getting player who uses a weapon. if ( ToBaseEntity( pPlayer ) == NULL ) then -- returning if player is not valid ( basic check ) return; end endThen there are primitive functions, animations, sound, subtraction of bullets from the clip:
function SWEP:PrimaryAttack() local pPlayer = self:GetOwner() --getting player who uses a weapon. if ( ToBaseEntity( pPlayer ) == NULL ) then -- returning if player is not valid ( basic check ) return; end if ( self.m_iClip1 <= 0 ) then --checking for a empty clip if ( not self.m_bFireOnEmpty ) then self:Reload(); else self:WeaponSound( 0 ); self.m_flNextPrimaryAttack = 0.3; end return; end self:WeaponSound(1) --emit a shoot sound from SoundData self:SendWeaponAnim(ACT_VM_PRIMARYATTACK) --do the animation of viewmodel pPlayer:SetAnimation( 5 ) --do the animation of player self.m_iClip1 = self.m_iClip1 - 1; --remove one ammo from clip self.m_flNextPrimaryAttack = gpGlobals.curtime() + 0.10; --next primary attack after shoot endOkay, after that, i gonna show how to do the function for bullet, and recoil:
function SWEP:PrimaryAttack() local pPlayer = self:GetOwner() --getting player who uses a weapon. if ( ToBaseEntity( pPlayer ) == NULL ) then -- returning if player is not valid ( basic check ) return; end if ( self.m_iClip1 <= 0 ) then --checking for a empty clip if ( not self.m_bFireOnEmpty ) then self:Reload(); else self:WeaponSound( 0 ); self.m_flNextPrimaryAttack = 0.3; end return; end self:WeaponSound(1) --emit a shoot sound from SoundData self:SendWeaponAnim(ACT_VM_PRIMARYATTACK) --do the animation of viewmodel pPlayer:SetAnimation( 5 ) --do the animation of player self.m_iClip1 = self.m_iClip1 - 1; --remove one ammo from clip self.m_flNextPrimaryAttack = gpGlobals.curtime() + 0.10; --next primary attack after shoot local vecSrc = pPlayer:Weapon_ShootPosition(); --these two parametrs must be defined! local vecAiming = pPlayer:GetAutoaimVector( 0.08715574274766 ); -- vecSrc - position of fire, vecAiming - Directory where is shooting, bullet spread, distance, Ammo Type local info = FireBulletsInfo_t(1, vecSrc, vecAiming, vec3_origin,4096, self.m_iPrimaryAmmoType) -- actually BulletInfo table info.m_pAttacker = pPlayer --defining our attacker pPlayer:FireBullets( info ) --and shoot the bullet with info from table pPlayer:ViewPunch( QAngle( -0.5, random.RandomFloat( -1, 1 ), 0 ) ); -- recoil end
Reload
Reload is must be ALWAYS look like that:
function SWEP:Reload() ToHL2MPPlayer(self:GetOwner()):DoAnimationEvent( 3 ) -- do the reload animation return self:DefaultReload( self:GetMaxClip1(), self:GetMaxClip2(), 182 ); --actually reload our gun end
JOIN HL2GMED DISCORD SERVER!