From Valve Developer Community
Jump to: navigation, search

How to make a Laser Pistol!


Warning.png Warning: This will replace the original pistol in your mod.

We will make changes in four files:

  • weapon_pistol.cpp - contains the code that makes the pistol work
  • hl2_gamerules.cpp - contains code that determines what the engine does
  • weapon_pistol.txt - this is the weapon script for the pistol
  • skill.cfg


First we need to add some #include directives to get access to the functions and classes that we will need to make a laser. The first file we need is beam_shared.h, which contains a great deal of code relevant to using beams. The other file we need is ammodef.h.

To include these files, change the line that reads #include "gamestats.h" to:

	#include "gamestats.h"	

	#include "beam_shared.h"	/* We will use some of the functions declared this later... */
	#include "ammodef.h"		/* This is needed for the tracing done later */

	// This determines the sprite used by the laser beam
	#define PHYSCANNON_BEAM_SPRITE "sprites/orangelight1.vmt"
Note.png Note: We also added #define PHYSCANNON_BEAM_SPRITE. We use this macro wherever we want to refer to the sprite used to draw the laser beam. Later, if we want to change the sprite that gets used, all we have to do is change "sprites/orangelight1.vmt" to something else.

The next thing that we need to do is to declare two functions, DrawBeam and DoImpactEffect. DrawBeam will actually draw a laser beam for us (once we define it). DoImpactEffect is special because it gets called automatically by the game engine. We are allowed to define it so that it does something for us. We will define it to create an electrical explosion wherever the laser hits. These two functions will be defined later.

  • Under public, below DECLARE_SERVERCLASS(), add the following:
	void   	DrawBeam( const Vector &startPos, const Vector &endPos, float width );
	void	DoImpactEffect( trace_t &tr, int nDamageType );

Next, we need to add a variable. Whenever we add a variable, we also must add it to the weapon's DATADESC section. This will allow the variable's content to be stored and loaded in saved games, keeping states consistent between game sessions.

Under private, below DECLARE_ACTTABLE(), add the following:

	int	m_nBulletType;

Then, below BEGIN_DATADESC( CWeaponPistol ) add:


The next step is to change the declaration of the PrimaryAttack function so that it receives more information from the game engine about what is happening when the pistol is attacking. Locate the following:

void	PrimaryAttack( void );

and change it to

void	PrimaryAttack( trace_t &tr, int nDamageType, CBaseCombatCharacter *pOperator );

To do: Find a reference that proves that this works.

Remember that variable we added earlier (m_nBulletType)? Like any other variable, we ought to initialize it in the weapon's constructor. The code for the constructor starts like this:

CWeaponPistol::CWeaponPistol( void )
	m_flSoonestPrimaryAttack = gpGlobals->curtime;

To make sure that that variable gets initialized when the weapon is created, change the above to look like this:

CWeaponPistol::CWeaponPistol( void )
	m_flSoonestPrimaryAttack = gpGlobals->curtime;
	m_nBulletType = -1;

The PrimaryAttack function is called every time the weapon attacks. We need to change it to match the the change we made above. We also need to add code to fire a laser. First, locate the following:

void CWeaponPistol::PrimaryAttack( void )

and change it to

void CWeaponPistol::PrimaryAttack( trace_t &tr, int nDamageType, CBaseCombatCharacter *pOperator )

Next, find the following in the PrimaryAttack function:

	gamestats->Event_WeaponFired( pOwner, true, GetClassname() );

and add the following code below it:

	Vector vecShootOrigin, vecShootDir;
	vecShootOrigin = pOperator->Weapon_ShootPosition();
	DrawBeam( vecShootOrigin, tr.endpos, 15.5 );

The above code calls our DrawBeam function (defined next) with two vectors and a float. The first vector specifies where the beam should start, the second specifies where it ends. The second vector comes from the tr parameter to PrimaryAttack. It represents the location of whatever was is in the line of fire of the pistol. So DrawBeam will draw a laser beam from the barrel to wherever the pistol is aiming, with a beam width of 15.5.

To do: This information is probably best broken up and distributed throughout the tutorial.

Finally, we have to define the DrawBeam and DoImpactEffect functions.

// Purpose: 
// Input  : &startPos - where the beam should begin
//          &endPos - where the beam should end
//          width - what the diameter of the beam should be (units?)
void CWeaponPistol::DrawBeam( const Vector &startPos, const Vector &endPos, float width )
	//Tracer down the middle
	UTIL_Tracer( startPos, endPos, 0, TRACER_DONT_USE_ATTACHMENT, 6500, false, "GaussTracer" );
	//Draw the main beam shaft
	CBeam *pBeam = CBeam::BeamCreate( PHYSCANNON_BEAM_SPRITE, 15.5 );
	// It starts at startPos
	pBeam->SetStartPos( startPos );
	// This sets up some things that the beam uses to figure out where
	// it should start and end
	pBeam->PointEntInit( endPos, this );
	// This makes it so that the laser appears to come from the muzzle of the pistol
	pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
	pBeam->SetWidth( width );
//	pBeam->SetEndWidth( 0.05f );

	// Higher brightness means less transparent
	pBeam->SetBrightness( 255 );
	pBeam->SetColor( 255, 185+random->RandomInt( -16, 16 ), 40 );
	// The beam should only exist for a very short time
	pBeam->LiveForTime( 0.1f );
// Purpose: 
// Input  : &tr - used to figure out where to do the effect
//          nDamageType - ???
void CWeaponPistol::DoImpactEffect( trace_t &tr, int nDamageType )
	//Draw our beam
	DrawBeam( tr.startpos, tr.endpos, 15.5 );
	if ( (tr.surface.flags & SURF_SKY) == false )
		CPVSFilter filter( tr.endpos );
		te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
		m_nBulletType = GetAmmoDef()->Index("GaussEnergy");
		UTIL_ImpactTrace( &tr, m_nBulletType );

To do: add more comments and/or explain what does what and why


Now that we have finished changing the pistol code, we need to change some engine code so that the laser pistol works as expected. Locate the following:

def.AddAmmoType("Pistol", DMG_BULLET, TRACER_LINE_AND_WHIZ, "sk_plr_dmg_pistol", 
						 "sk_npc_dmg_pistol", "sk_max_pistol", BULLET_IMPULSE(200, 1225), 0 );

The line shown above sets up some information that the game engine uses to determine how getting shot by the pistol affects whatever is being shot. Change it to look like the following:

def.AddAmmoType("Pistol", DMG_DISSOLVE, TRACER_NONE,  "sk_plr_dmg_pistol", 
						 "sk_npc_dmg_pistol", "sk_max_pistol", BULLET_IMPULSE(200, 1225), 0 );

Changing DMG_BULLET to DMG_DISSOLVE changes what happens when an enemy is killed by this weapon. In this case, when an enemy is killed, it dissolves as if it was killed by the AR2 secondary fire. Changing TRACER_LINE_AND_WHIZ to TRACER_NONE gets rid of the tracer effect that can be seen when firing the pistol.


This file is located in your mod folder, under scripts.
The path to this folder is usually something like C:\Program Files\Steam\steamapps\SourceMods\<your mod name>\scripts\

We are almost finished with our awesome laser pistol. However, if we ran our code now, we wouldn't see a "Laser Pistol" in our weapons menu. Instead we would still see a "9mm Handgun" or something like that. To fix this, we have to change a single line in the pistol's weapon script.

Change the following:

"printname"	"#HL2_Pistol"


"printname"	"LASER PISTOL"

This changes the name of the weapon as it appears in the HUD

Tip.png Tip: If you know how, you can change the "SoundData" field so that when you fire the pistol, it sounds like it fires a laser.


This file is located in your mod folder, under cfg.
The path to this folder is usually something like C:\Program Files\Steam\steamapps\SourceMods\<your mod name>\cfg\

We have one more edit to make. The pistol doesn't fire bullets anymore, it fires laser beams. Those little 9mm bullets should probably do less damage than a laser. Therefore, we should change the amount of damage that the laser pistol does.

Change this:

	sk_plr_dmg_pistol		"5"
	sk_npc_dmg_pistol		"3"
	sk_max_pistol			"148"

to this:

	sk_plr_dmg_pistol		"20"
	sk_npc_dmg_pistol		"15"
	sk_max_pistol			"148"

To do: is sk_npc_dmg_pistol the amount of damage the pistol does to NPCs or is it the amount of damage that NPCs do when they use the pistol?

A message from the original author

I hope this helps u a bit
Speedlly (Scubic)
this weapon (or a part of it) is going to play a role in the game that were maken (Cubic Life)