Ask the map questions - what is in the way, can this point see that one, what does a bullet do to a wall.
The world module answers questions about geometry. It does not list entities - that is ents - it tells you what a line, a box or a bullet would run into between two points.
on( "frame", function( canvas )
local me = ents.local_pawn( )
if not me then return end
local from = me:eye( )
local result = world.trace( from, from + me:eye_angles( ):forward( ) * 4096 )
if result.hit then
print( string.format( "something %.0f units ahead", result.fraction * 4096 ) )
end
end )
The collision layer the trace is made on, 0 to 255.
4
mins, maxs
Two vec3s: sweeps a box with those corners along the ray instead of a thin line. Both are needed.
none
radius
Sweeps a ball of that radius along the ray. Wins over mins and maxs.
none
The result is a table:
Field
Meaning
fraction
How far along the ray it got before hitting something: 0 right at from, 1 all the way to to.
hit
true when something was hit - that is, when fraction is below 1.
start_solid
true when the ray started inside something solid.
pos
Where the ray ended: the hit point, or to when it hit nothing.
normal
The direction the surface it hit faces.
entity
The entity it hit, or nil for the map itself.
contents
The engine's contents bits of what it hit.
-- is there a ceiling above my head?
local me = ents.local_pawn( )
local head = me:eye( )
local up = world.trace( head, head + vec3( 0, 0, 72 ) )
if up.hit then
print( "room for", math.floor( up.fraction * 72 ), "units" )
end
#world.visible( from, to [, target [, skip]] ) → boolean
Whether the ray from from to to arrives unobstructed. target is an entity: if the ray is stopped by it, the end point still counts as visible - what you want when to is a point inside a player, such as the head. skip is the entity the ray passes through, the local player's pawn by default.
local head = player:bone( ents.bone.head )
if world.visible( me:eye( ), head, player ) then
-- a clear line from my eyes to their head
end
A bullet that meets a wall is not simply stopped: it loses damage, it may come out on the other side with some left, and what it does depends on the material. The cheat uses the engine's own routine to work this out, and world.bullet gives a script the same answer.
#world.bullet( from, direction [, options] ) → table | nil
Runs the engine's bullet simulation from from along direction with the data of a weapon, and reports what the walls do to the bullet.
from - a vec3, where the bullet starts. For the muzzle use me:eye().
direction - a vec3 pointing the way the bullet flies. It does not have to be normalised. To go from view angles, use angles:forward().
options.weapon - a weapon entity whose damage, penetration and range are used. By default the weapon the local player holds.
The result:
Field
Meaning
damage
The damage left after the last surface the bullet got through, before the hitgroup multiplier. world.damage applies that.
penetrated
true if the bullet went through at least one surface.
surfaces
How many surfaces it went through.
contacts
A list, in order, of everything it met: { distance, damage, penetrated } - how far from from the contact is, the damage the bullet had there, and whether it got through.
nil when the simulation cannot run: the weapon cannot penetrate (a knife, a grenade), the weapon's data is not available, or the engine's routines were not found.
on( "frame", function( canvas )
local me = ents.local_pawn( )
if not me or not me:weapon( ) then return end
local eye = me:eye( )
local hit = world.bullet( eye, me:eye_angles( ):forward( ) )
if hit then
local width, height = canvas:screen( )
canvas:text( width / 2 + 12, height / 2, string.format( "%d dmg after %d wall(s)", math.floor( hit.damage + 0.5 ), hit.surfaces ),
color( 255, 255, 255 ), { shadow = true } )
end
end )
What the local player's current weapon does to a player at full strength - no walls, no distance - for a hitgroup, after armour and the server's damage scales. hitgroup is a number from ents.hitgroup.
options:
Field
Meaning
Default
armor
The target's armour.
0
helmet
Whether the target wears a helmet.
false
team
The target's team: 2 terrorists, 3 counter-terrorists. The damage scales differ by team.
2
Combine the two calls for an expected damage: the bullet's remaining damage is the weapon's damage after the walls, and world.damage is the weapon's damage at full strength, so their ratio is the share that survives.
local full = world.damage( ents.hitgroup.head, { armor = 100, helmet = true, team = 3 } )
local behind = world.bullet( eye, direction )
if behind then
local share = behind.damage / weapon:damage( )
print( string.format( "a headshot through that wall would do about %d", full * share ) )
end