# 12. Weapons¶

## 12.1. Gauss¶

The gauss is one of the more interesting weapons in Half-Life. One of the earliest speedrunning tricks, the simple gauss boosting, and one of the most recently discovered tricks, quickgaussing, are both gauss-related. The gauss is arguably the most complex weapon in Half-Life, and it is worth devoting some paragraphs exploring its behaviour.

The gauss weapon has two modes, as any entry level Half-Life player would know. The primary mode of the gauss fires orange beams consuming 2 cells and providing 20 damage. The delay between shots in primary mode is 0.2s. The secondary mode is more interesting. In single-player mode, the weapon consumes a cell every 0.3s while charging, starting from an initial consumption of one cell. The minimum charge time is 0.5s. If the weapon charges for more than 10 seconds, the weapon will discharge and inflict 50 damage onto the player. The damage of the beam in secondary mode otherwise scales linearly with charging time such that

Observe that the damage caps at 200 after charging for 4 seconds. The secondary fire produces a physical recoil, which is manifested by a change in the player velocity. If is the current player velocity, and is the unit forward vector, then the new velocity is given by

(12.1)

where refers to the diagonal matrix with 1, 1, and 0 as the entries on the diagonal. Observe that the vertical velocity never changes. To maximise horizontal speed change, the player must fire from zero pitch, which gives the maximum speed change of 1000 ups, one of the greatest speed boosts available in Half-Life.

The behaviour of gauss beams is relatively complex compared to other Half-Life projectiles. Intuitively, players recognise that gauss beams have a tendency to reflect off surfaces. Gauss beams can also “punch” through walls and damage entities at the opposite side, through a mechanism that is not obvious at first sight. Gauss beams can even inflict damage onto oneself under the right circumstances. What is more, the damage from gauss beams can be seemingly amplified when fired through particular geometries.

A detailed and complete understanding of the gauss behaviour can be achieved by reading the code in dlls/gauss.cpp in the Half-Life SDK. Rather than listing the code and tracing through line by line here, we shall explore the weapon by examples of its exploits.

### 12.1.1. Beam iterations¶

A gauss beam starts off with an initial damage and hit counter nMaxHits with an initial value of 10. The game then perform at most 10 iterations (tracked by nMaxHits which is decremented each iteration) to to calculate the dynamic behaviour of the gauss beam. In each iteration, the game may reduce the damage, inflict damage to some entity, or calculate beam reflection. If or nMaxHits reaches zero at some iteration , then the beam will stop iterating. This implies that the damage is akin to the “energy” of the beam.

Crucially, the game also keeps track of the ignored entity, or pentIgnore in the code. This ignored entity is initialised to be the player entity before the iterations begin. The ignored entity is the entity that will be ignored by any line tracing, and can be changed from time to time as we will see shortly. What entity is or is not being ignored plays a huge role in some of the common exploits of this weapon.

In performing line traces, the game also keeps track of , represented by vecDir in the code. You can think of this vector as representing the direction of a the gauss beam in any iteration. This direction vector is initialised to be the player’s unit forward vector . It can be modified if the beam reflects, as we will see below.

Roughly speaking, in any iteration , the game begins by tracing a line from the player gun position to 8192 units away in the direction of , namely with the end point of . This line may or may not hit some entity. If no entity is hit, the iterations simply stop. Otherwise, the behaviour of the beam will depend on whether this entity is gauss reflectable (GR) or non-gauss reflectable (non-GR). For our purposes, we can say that an entity is gauss reflectable if it cannot receive damage, and vice versa.

Note

The game graphics will sometimes show a gauss beam seemingly reflecting off a non-gauss reflectable entity. This does not contradict what we described here: what you see is purely a client side visual artefact, and no reflection actually occurred on the server side. You can check this by placing an NPC in the path of the apparent reflected beam, and observe that the reflected beam does not damage the NPC.

Denote the point of intersection of the tracing line and the hit entity. If the hit entity is non-GR, then the game will simply set the trace origin of the next iteration . This implies that the next trace origin is not exactly at the point of intersection, but displaced 1 unit away. Also, the game will set the pentIgnore to be the hit entity. This causes the line trace in the next iteration to ignore this entity. The game now proceeds to the next iteration.

On the other hand, if the hit entity is GR, then the beam behaviour is more complex. The game first sets the ignored entity pentIgnore to null, which causes the subsequent line traces in this iteration to not ignore anything. Then, the game decides whether to reflect the beam. If is the plane normal of the hit surface and is the current beam direction vector, then the game calculates the component of the beam in the direction of the plane normal, that is . This quantity can also be thought of this way: if is the angle of incidence (the shortest angle between the beam and the plane normal), then this quantity equals .

A gauss beam can reflect only if , which implies an angle of incidence larger than 60 degrees. If the beam reflects, the game will set the beam direction to be . This new direction represents the direction of the reflected beam. Observe that the angle of reflection is the same as the angle of incidence, because

Then the game will set for the next iteration. Notice that the line trace source for the next iteration is displaced 8 units away from the point of reflection. Following this, the game will create an explosion with the origin at and a source damage of (see Explosions). This implies that the larger the angle of incidence, the lower the blast damage. Finally, the game calculates the damage for the next iteration. The game then proceeds to the next iteration.

On the other hand, if the beam cannot reflect, which implies an angle of incidence of less than 60 degrees, then the subsequent beam behaviour is the most complex. The game first checks if the beam has reached this point in the previous iterations. If so, the iterations will simply stop. Otherwise, now that the beam has just reached this point in the code, that check will fail for subsequent iterations. In addition, if this gauss beam is fired from the primary mode, then the game will also stop the iterations.

The game traces a line from to . Note that always lies on the line from to . If the trace result is all solid, the game moves on to the next iteration. Otherwise, set the tracing point of intersection be . Now, the game attempts to trace backwards by tracing from to . Set the tracing point of intersection be . Now, denote

If , the game moves on to the next iteration. Otherwise, if set . The game now calculates . With this new damage, the game then creates an explosion with the origin at and source damage . Finally, the game sets .

### 12.1.2. Simple gauss boost¶

One of the simplest tricks for the gauss weapon is simple gauss boosting. Namely, speed boosting from the recoil of firing the secondary attack. The simple gauss boost remains one of the most versatile boosting methods in Half-Life, and is used to great effects in a typical Half-Life speedrun. Unfortunately, the gauss being an endgame weapon is manifested by the fact that its ammo supply is relatively constrained. Good ammo planning must be done to maximise the effectiveness of this weapon.

A common task in speedrunning is to get from one point to another in the shortest time possible using simple gauss boosting. From (12.1) we know that, assuming zero pitch, the horizontal speed boost is proportional to the charging time. On the other hand, the minimum charging time is 0.5 seconds. What is the optimal way to perform gauss boosts? Or, what is the boosting scheme for maximising the average speed (total distance travelled in a given time)? Should one repeatedly charge the gauss for 1s and firing, or repeatedly charge the gauss for 0.5s and firing? There is a simple way to answer this.

Suppose the player is stationary. At , the player begins charging and after an interval , the player releases the charge. Immediately after the release, the player begins charging again for , and so on. From Fig. 12.3. we observe that the smaller the boosting interval, the closer the graph approximates the continuous boosting line, which is a theoretical case of . More importantly, observe that the area under the discrete graph also increases with decreasing , up to a maximum corresponding to the continuous case. Given that the minimum is half a second, we conclude that the optimal boosting scheme is to charge for half a second a firing, repeatedly.

If it is possible to pre-charge the gauss weapon before timing a particular run, then it is still beneficial to charge the weapon as much as possible and then release the charge at . This gives a higher initial speed in Fig. 12.3. instead of 0 as shown, which effectively shifts the graphs upwards and increasing the area under the graphs.

### 12.1.3. Quickgauss¶

Quickgauss is a special kind of speed boosting similar to the simple gauss boost, except a save/load is done while the gauss is charging. When the charge is released after a game load, the result is similar to releasing a secondary charge. In particular, the resulting speed boost and damage are the maximum attainable from the weapon, that is 1000 ups and 200 damage, while consuming only one cell and a charging time of half a second. This provides one of the highest accelerations from a single weapon achievable in game (2000 ups/s), and also one of the highest damage rates (400 dps).

Unfortunately, quickgauss only works in versions of Half-Life with the bunnyhop cap. This is because in these versions of Half-Life, in dlls/weapons.cpp the following lines define the states of the gauss weapon to be stored in the savestate:

TYPEDESCRIPTION CGauss::m_SaveData[] =
{
DEFINE_FIELD( CGauss, m_fInAttack, FIELD_INTEGER ),
//  DEFINE_FIELD( CGauss, m_flStartCharge, FIELD_TIME ),
//  DEFINE_FIELD( CGauss, m_flPlayAftershock, FIELD_TIME ),
//  DEFINE_FIELD( CGauss, m_flNextAmmoBurn, FIELD_TIME ),
DEFINE_FIELD( CGauss, m_fPrimaryFire, FIELD_BOOLEAN ),
};
IMPLEMENT_SAVERESTORE( CGauss, CBasePlayerWeapon );


Notice how the highlighted line is inexplicably commented out, so that m_flStartCharge does not get saved to the savestate. When the game is loaded from a save, this field will be zero. The calculation of current charging time is done by gpGlobals->time - m_pPlayer->m_flStartCharge throughout dlls/gauss.cpp, with gpGlobals->time being much larger than 4 in most cases. If m_flStartCharge is zero, the calculated charging time will be much larger than 4, and thus clamped to 4 and giving the maximum damage and recoil. On the other hand, the consumption of cells while charging is done periodically over a real passage of time, rather than calculated from the charging time. Since the real charging time is only half a second, only one cell is consumed in total.

It should be immediately apparent that quickgaussing is very powerful. If quickgauss is available in a particular version of Half-Life, the runner will almost never need to use the simple gauss boosting, as quickgauss is so ammo efficient. In the rare cases where it is desirable to perform a boost less than the maximum attainable, the runner can pitch up or down accordingly when firing to reduce the boost amount, according to (12.1).

### 12.1.4. Entity piercing¶

When a beam hits a non-gauss-reflectable entity, which implies it is damageable, the beam will first inflict damage onto the entity. Then, in the next iteration, the beam will ignore that entity while continue tracing forward. This results in the beam passing right through the entity untouched, and hitting some other entity instead. It is also important to note the beam does not lose energy when it passes through non-GR entities. Understanding entity piercing allows the runner to save time and ammo by reducing the number of shots required to damage multiple targets.

### 12.1.5. Multigauss¶

Multigauss refers to the gauss beam hitting a non-gauss-reflectable entity, reflecting on some adjacent gauss-reflectable entity, and then hitting the same entity again with the reflected beam. In addition, a small radius damage is inflicted onto the entity as the beam reflects. Multigauss is useful for getting double the normal damage out of gauss beams for free.

As explained in Entity piercing, when a gauss beam hits a non-gauss-reflectable entity, it will inflict damage onto the entity. This is shown by the red portion of the beam in Fig. 12.4.. In the next iteration, the beam will ignore the entity that got hit, passing right through the entity. Suppose the beam then hits a gauss-reflectable entity, such as the ground or wall. If the angle of incidence is greater than 60 degrees (a necessary condition for the beam to reflect), the beam will reflect off the GR entity, as explained in Beam iterations.

Whenever a gauss beam reflects, a radius damage will be applied from the point of reflection. This is a little known fact among Half-Life players. Suppose the angle of incident is . Then the radius damage is calculated to be . This radius damage will be inflicted onto the non-GR entity, though the final amount obviously depends on how far away the entity is from the point of reflection. In the most common case, the non-GR entity is simply in contact with the GR entity. For instance, a damageable crate (non-GR) is usually in contact with the ground (GR). As a result, the distance of the non-GR entity from the point of reflection will be zero, causing 100% of the radius damage to be inflicted onto it.

At the end of the second iteration, the gauss beam will no longer ignore the non-GR entity that got hit in the first iteration. Therefore, the reflected beam will hit the entity in question again in the third iteration provided the entity is sufficiently thick (otherwise you would be triggering a bypass instead, as explained in Reflection bypass), though with a damage of . Overall, the damages inflicted onto the entity in question is shown in the table below.

Iteration Damage
First
Second
Third

The total damage inflicted onto the non-GR entity is simply the sum of all damages, which has a maximum of , or twice the damage. Notice how the total damage is independent of the angle of incident . The only reason that causes the total damage to be less than is the non-GR entity located at a distance away from the point of reflection. Never the less, even if we ignore the radius damage, the total damage inflicted onto the entity is still greater than the damage of a normal beam alone.

### 12.1.6. Entity punch¶

As explained in Beam iterations, a secondary gauss beam can punch through a GR entity if it does not meet the criterion for reflection. The damage produced by an entity punch is dependent on . This quantity is typically the thickness of the wall, but this is not always the case. In particular, the position is found by tracing a line from the inside an entity. It is not always obvious what the line can “see” and end up under these circumstances. Sometimes, the trace line can ignore (unrelated to pentIgnore) and not able to detect certain entities, and therefore the line tracing may end at a further point, skipping these undetected entities along the way. And sometimes, if the thickness of an entity is too high, the game may wrongly determine that the trace is all solid.

If the line tracings went well, the game will create an explosion 8 units away from the exit point. The thinner the walls or entities (barring the caveats above), the higher the explosive damage. Since the explosion origin is displaced from the exit surface, it is possible for the origin to be located inside some other entity, thus causes nuking (see Nuking). In general, entity punching can be very powerful. With a full gauss charge, the player can instantly create explosions of a maximum of 200 source damage, outclassing most explosive weapons.

### 12.1.7. Reflection boost¶

Reflection boost refers to boosting which involves a reflection of the gauss beam. There are two variants of gauss reflect boost: ducking and standing. Reflection boosts can be used to provide vertical boost, which is not possible with a normal gauss boost in single player. The vertical boost is provided by means of self-inflicted damage, which can be costly to player health.

The ducking reflect boost sequence is as follows.

1. Start charging for quickgauss
2. Duck on the ground
3. Pitch to 30 degrees downward
4. Jump just before firing

The beam should be reflected off the ground, at a 60 degrees angle of incidence. This provides the player a 866 ups horizontal boost and a respectable vertical boost. The sequence demands high precision to produce the desired effects.

The standing reflect boost uses explosive damage from beam reflection as well. The standing reflection boost essentially works by performing a self-inflicted multigauss (Multigauss). However, the standing reflect boost sequence requires even higher precision to execute.

1. Start charging for quickgauss
2. Stand touching a wall
3. Pitch to 60 degrees downward
4. Yaw to look perpendicularly into the wall
5. Offset the yaw slightly to the left or right by about 1 to 2 degrees
6. Duck and jump simultaneously just before firing

The result, however, is respectable.

### 12.1.8. Selfgauss¶

Selfgauss is a very well known trick, but probably one of the least understood among speedrunners. Selfgaussing is the result of the beam hitting the player as it is being fired out of the imaginary gun barrel, or specifically the player’s gun position. This is due to the origin of the line tracing being inside the player model. An analogy from the real world would be firing a pistol from inside one’s body, so that the bullet hits the player’s internals point blank. The outcome is a perfectly vertical speed boost, as the inflictor origin and the player origin coincides, thus giving a perfectly upward vector (see Damage boosting).

Caution

It is a common misconception that selfgauss occurs because the beam somehow “reflects” backwards onto the player after hitting a wall. It is easy to see that this is a wrong explanation, because the beam cannot reflect when the angle of incidence is less than 60 degrees, and the gauss beam cannot reverse its damage inflicting direction.

In the first iteration, the gauss beam will ignore the player, because pentIgnore is set the be the player entity, as explained in Beam iterations. Selfgauss will only work in the next iteration if pentIgnore is set to null, and . Therefore, selfgauss cannot happen if the beam strikes a non-gauss reflectable entity, for it modifies in the next iteration. Selfgauss cannot happen if the beam reflects, as reflections change as well.

Suppose when the player fires the gauss in secondary mode, the beam first strikes some entity at a sufficiently small angle of incidence so that the beam does not reflect. Assuming this entity is gauss reflectable, the game will perform two traces to determine the distance between the “exit point” and the entry point. This distance is denoted as . Selfgauss will only work if is less than the numerical damage of the beam. If the opposite is true, then will be modified, preventing selfgauss. This implies that higher is more desirable as it allows for selfgaussing with a greater damage, and thus producing greater boosts. The same caveat with regards to the meaning of should be applied, as explained in Entity punch. Namely, while it commonly is found to be the thickness of the entity the beam is hitting, this is not always the case. It is not always easy to tell at first sight what might be for a given geometry and terrain.

To perform selfgauss in practice, there are a few notes to keep in mind. Recall from Hitgroup that attacks that trace to the player’s head will deal three times the original damage. To save ammo, it is desirable to headshot the player while selfgaussing, giving a higher speed boost to ammo ratio. In addition, it is desirable to jump immediately before selfgaussing, as jumping provides an important initial vertical speed that can save health and ammo. However, note that a simple jump may not work. Recall from Duckjump that when the player jumps, the player model plays the jumping animation, which changes the model geometry (and thus the hitboxes’ positions) considerably. This can prevent headshotting even when the beam is fired from the same viewangles without jumping. The solution is to duck and jump, which prevents the jumping animation from playing.

### 12.1.9. Doublegauss¶

The doublegauss is a way of doubling the damage of a secondary gauss attack using the same number of cells and charge time. Doublegauss works very similarly to selfgauss (Selfgauss). The only difference is that, in the first beam iteration, the beam should hit the target entity which must be non-GR. As a result, the first damage will be inflicted and will be calculated to be inside the target entity. The rest of the mechanism work exactly the same as that of selfgauss, except the trace origins are inside the target entity rather than the inside the player entity. Specifically, the beam will ignore the target entity in the second iteration and inflict a second unattenuated damage onto the entity in the third iteration. This implies that the conditions for triggering doublegauss are the same as selfgauss as though the target entity were not there.

### 12.1.10. Gauss rapid fire¶

When firing the gauss in the primary mode, there is a small delay between shots, similar to how other weapons behave. However, unlike other weapons in Half-Life, if a save/load is performed immediately after a primary fire, this firing delay will be eliminated entirely. Consequently, it is possible to fire the gauss at a dramatic rate, dishing out an extreme damage rate. For instance, each primary fire deals 20 damage. At 1000 fps, it is possible to fire the weapon at a rate of 1000 times per second, for a total of 50 shots (recall that each primary fire consumes 2 out of 100 cells). This results in an impressive 1000 damage in just 0.05 seconds. The downside, of course, is the dramatic ammo consumption.

Gauss rapid fire is useful in situations where gibbing damageable entities as quick as possible is of utmost consideration, thanks to the primary fire’s ability to gib corpses. For example, clearing monsters in a narrow pathway which obstruct the runner’s path. The runner should always headshot monsters if possible to obtain a three times damage boost. The weapon should be continuously fired even as the corpse is slowly falling after the monster is dead.

### 12.1.11. Reflection bypass¶

The reflection bypass refers to a method of causing the gauss beam to reflect and bypass a solid obstruction. Unlike the traditional way of punching through a wall using the secondary attack, this method relies on shooting very close to an edge so that the origin of the reflected beam at some iteration is outside the obstructing entity. This works because the origin of the reflected beam is 8 units away from in the direction of the reflected vector . This 8 units skip in space allows bypassing any entity of any type of sufficient thinness. This trick works on both GR and non-GR entities, and for both primary and secondary shots.

This trick is useful for getting the beam to hit some entity on the other side of some thin obstruction with less than 8 units thickness. Although 8 units thin entities are relatively rare in Half-Life, it is not unusual to find them from time to time. The downside of this trick is that the beam loses some damage after reflection.

## 12.2. Hornet gun¶

The hornets created in primary fire has initial velocity

where is the player’s unit forward vector. Hornets created in second fire has initial velocity

In both cases, the initial velocity is independent of the player velocity.

TODO

TODO

## 12.3. Tripmine¶

The handgrenade is one of the most useful weapons for damage boosting in Half-Life. It is versatile and can be used in many situations. However, making a handgrenade land and explode at the right location can be tricky due to its bouncy nature and the delayed detonation.

The handgrenade experiences entity gravity and entity friction , and moves with type MOVETYPE_BOUNCE. As a result, the handgrenade experiences only half of the gravity experienced by the player. In addition, recall from Collision that, if the entity friction is not 1, then a MOVETYPE_BOUNCE entity has bounce coefficient , which, in the case of the handgrenade, is numerically . This is why a handgrenade bounces off surfaces unlike other entities.

Interestingly, the initial speed and direction of the grenade when it is tossed depend on the player pitch in a subtle way. For example, when (i.e. the player is facing straight down) the initial speed and direction are and respectively. However, when the initial speed and direction now become and respectively. Another notable aspect of handgrenades is that its initial velocity depends on the player velocity at the instant of throwing. This is unlike MP5 grenades.

In general, we can describe the initial velocity and direction of handgrenades in the following way. Assuming all angles are in degrees. First of all, the player pitch will be clamped within . Let be the handgrenade’s initial pitch, then we have

And if is the current player velocity, is the grenade’s initial velocity, and is the unit forward vector computed using and player’s , then

To visualise this equation, we plotted Fig. 12.7. which depicts how the handgrenade’s relative horizontal speed and vertical velocities vary with player pitch.

From Fig. 12.7., we can make a few observations to understand the handgrenade throwing angles better. Firstly, player pitch within , the curve is a circular arc. This is because the relative speed of the full 3D relative velocity vector is exactly , since in this range . Player pitch beyond the non-smooth point at corresponds to a less trivial curve, however, as the relative speed itself varies with the pitch. A second observation we can make is that, for the vast majority of player pitch, the relative vertical velocity is positive or pointing upward. There exist some pitch angles that result in downward vertical velocity, and these angles may be useful under certain circumstances. A third observation is that, there is a difference between throwing backwards by rotating by 180 degrees and keeping the same, versus keeping the same and setting . For example, although the player’s unit forward vector is exactly the same when and , and when and , observe that the throw velocity is quite different. Indeed, by having we obtain the maximum possible horizontal throwing velocity not attainable with the “normal” player pitch range in . A fourth observation is that, assuming the player pitch lies within , the relative horizontal velocity is invariant under the transformation . For example, the relative horizontal velocity at and is equal.

## 12.5. MP5¶

The bullets are spread in similar ways to shotgun bullets, except there is only one bullet per ammo. See Shotgun for a description of how bullet spreads are computed.

The MP5 is a fairly versatile weapon due to its ability to shoot 10 contact grenades. A contact grenade has an entity gravity . Therefore, an MP5 experiences only half of the gravity experienced by the player.

The MP5 grenade is unique in how its launch velocity is independent of current player velocity. This runs counter to real life physics, where an object initially stationary relative to a moving reference frame must have the same velocity as that of the reference frame, and therefore any additional velocity imparted onto the object must add to that. The MP5 grenade, on the contrary, always launches at velocity

where is the player’s unit forward vector. This peculiar behaviour can be advantageous in certain situations. For instance, we might want to “outrun” the grenade so that it explodes adjacent or behind us some time later.

It is possible to have two MP5 grenades touch each other and explode together.

The crowbar is

## 12.7. Shotgun¶

The shotgun is a very powerful weapon in Half-Life.

The primary attack of the shotgun fires 6 bullets and consumes 1 shell. The delay between shots is 0.75 seconds. The secondary attack fires 12 bullets and consumes 2 shells. The delay between shots is 1.5 seconds. Both the primary and the secondary attacks fire off multiple bullets, which is unique among Half-Life weapons. A special function called FireBulletsPlayer in combat.cpp is used to compute the damage tracings for shotguns and a few other weapons.

For each bullet, the game computes a pseudorandom direction vector which is then used for tracing attacks. The direction vector is randomised using the shared RNG (see Shared RNG), with the seed increased successively in a predictable way as the game iterates through all bullets. As there are only 256 possible ways to seed the shared RNG, so are there only 256 possible shotgun spread patterns.

## 12.8. Satchel charge¶

Similar to the hand grenade (Hand grenade), a satchel charge experiences entity gravity and entity friction , and has move type MOVETYPE_BOUNCE. One difference from hand grenades is that the entity gravity gets reset to 1 in the SatchelSlide touch function upon touching. Also, satchel charges float in water when its waterlevel is 3.

A satchel charge, when thrown, is created at the player origin rather than at the player’s view. The initial velocity is

where is the player’s unit forward vector. The satchel charge has an owner property that remembers who created it. The satchel charge will pass through the owner, but will collide with any other entity. The owner property is saved across save loads. It is also saved across map changes, provided the satchel charge does not disappear across transition. If it does disappear, the charge will lose information about who the owner is, and so will not be detonate and will collide with the original owner.