• Register
Post tutorial Report RSS Quake c - Traceline

Using traceline to find entities, do beam damage, and other cool stuff.

Posted by on - Intermediate Server Side Coding

What is traceline?

Quake-c defines it in defs.qc:

void (vector v1, vector v2, float nomonsters, entity forent) traceline = #16;

This is a builtin function run by engine c code.
I'll post the manual definition in a comment for reference.

When it is called by quake-c code, it does the following:

Trace a line between vector points v1 and v2 and set various variables.
Most quake-c code that uses traceline manipulates or derives action from one of those variables.

Call parameters:
v1 - vector source point in map space
v2 - vector end point in map space
nomonsters - if true monster entities will be ignored - we accept this as (ent.flags & FL_MONSTER)
forent - ignore this entity, and owner or owned entities, if world, ignore no entity

Notes: Traces are blocked by bounding boxes and exact bsp entities
- bounding boxes can be much bigger than visible models - setting FL_ITEM in flags gives a much bigger box, and monsters tend to have bigger boxes
- try this in the console: r_showbboxes is "1" ["0"] shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)

Globals from defs.qc (frequency of use in v1.06 quake-c by line count and manual notes):

entity trace_ent; // (22) entity hit by trace or world if none
float trace_allsolid; // (0) manual says "never used"
float trace_fraction; // (13) fraction of distance covered when entity was hit - 1 for no hits
float trace_inopen; // (7) true - line goes through CONTENT_EMPTY
float trace_inwater; // (7) true - line goes through CONTENT_WATER
float trace_plane_dist; // (0) distance to impact along direction vector
float trace_startsolid; // (0) manual says "never used"
vector trace_endpos; // (15) end of trace - v2, entity hit, or map surface
vector trace_plane_normal; // (11) tricky vector math - by the manual: "direction vector of trace"

Used in these functions of v1.06 quake-c:

ai.qc
client.qc
combat.qc
defs.qc
fight.qc
progdefs.h
shambler.qc
weapons.qc
wizard.qc

How does it really work in practice?

trace_ent:

Traceline only seems to set trace_ent to players or monsters if nomonsters is false.
It may be that it can target any entity with health and takedamage set. But in my experience it does NOT target non players and non monsters.
If you want to see most other entites a findradius of traceline length could be used:

findradius(v1, vlen(trace_endpos - v1));

and then check how close all the entity origins / box dimensions are to the traceline.
(I'll leave this vector math to you - just find the vlen from the entity origin to v1 and then trace that distance along the traceline vector (v1 - v2) - do another vlen compare between those two points and decide how close is close enough...)

trace_fraction:

If this is less than 1, the line stopped before the end point v2 was reached. There is no way to be sure if it is an accurate fraction - actual distance should be measured with vlen(org - end).

trace_endpos:

This is where the line stops in map coordinates. A great place for weapon effects (gunshot sparks or marks), portals, reticles, etc.

trace_plane_normal:

This is the tricky one!

Normal vector: "often simply called the "normal," to a surface is a vector perpendicular to it."
A vector perpendicular to the surface the traceline hit.
Say you wanted to place a portal or reticle in front of that surface:

// norm is a vector, e is the spawned entity to hold the mark or portal
// self is the firing entity, but the angles of the traceline could be used

norm = trace_plane_normal;
norm_x = 0 - norm_x;
norm_y = 0 - norm_y;
e.angles = vectoangles( norm );
makevectors(self.angles);
setorigin( e, pos - ( v_forward * 0.2 ) ); // subtract v_forward to move the mark away from the surface a short distance

vectoangles turns the normal into a vector pointing perpendicular away from the surface into open map space in front of the surface.

The other trace_* globals seem to work as indicated.
I have one caveat for the "never used" vars from frikbot source:

frikbot/bot_move.qc: if (trace_allsolid || trace_startsolid)

It seems like if these are true, the trace is either all in CONTENT_SOLID or just starts there.
I have not used these so I cannot verify this, but it would be easy to test out.

By use in the original code, traceline is mostly for weapon strike and damage.
The original lightning gun could potentially damage 3 targets. It ran 3 tracelines to find them along the beam strike.

A little imagination and traceline can (and has been) used for:
- targeting reticles
- placing portals and sprites (gunshot marks) on walls
- grapple hook operation
- bot and monster AI tracking
- chasecams

I hope this clears up the confusion around traceline.
Please ask any questions you have in the comments here, or on the forum: Moddb.com

Post comment Comments
numbersix Author
numbersix - - 2,244 comments

Darkplaces console variables that might affect traceline:

"apropos traceline" entered in the console provides:
(* apropos is a great search that returns all console vars, alias or commands that contain the search value)

cl_prydoncursor_notrace
- is "0" ["0"] disables traceline used in prydon cursor reporting to the game, saving some cpu time

collision_debug_tracelineasbox
- is "0" ["0"] workaround for any bugs in Collision_TraceLineBrushFloat by using Collision_TraceBrushBrushFloat

mod_q3bsp_optimizedtraceline
-is "1" ["1"] whether to use optimized traceline code for line traces (as opposed to tracebox code)

mod_q3bsp_tracelineofsight_brushes
- is "0" ["0"] enables culling of entities behind detail brushes, curves, etc

sv_gameplayfix_q1bsptracelinereportstexture
- is "1" ["1"] enables mods to get accurate trace_texture results on q1bsp by using a surface-hitting traceline implementation rather than the standard solidbsp method, q3bsp always reports texture accurately

5 results

Reply Good karma+2 votes
numbersix Author
numbersix - - 2,244 comments

Quake-c Manual ver 3.4 entry for traceline:

8.7 Collision checking

Function: traceline

traceline (vector v1, vector v2, float nomonsters, entity forent)
v1= start of line
v2= end of line
nomonster= if TRUE, then see through other monsters, else FALSE.
forent= ignore this entity, it's owner, and it's owned entities.
if forent = world, then ignore no entity.

Trace a line of sight, possibly ignoring monsters, and possibly ignoring the entity forent (usually, forent = self).
This function is used very often, tracing and shot targeting.
Traces are blocked by bounding boxes and exact bsp entities.
Returns the results in the global variables:

float trace_allsolid;
// never used
float trace_startsolid;
// never used
float trace_fraction;
// fraction (percent) of the line that was traced, before
// an obstacle was hit. Equal to 1 if no obstacle were found.
vector trace_endpos;
// point where line ended or met an obstacle.
vector trace_plane_normal;
// direction vector of trace (?)
float trace_plane_dist;
// distance to impact along direction vector (?)
entity trace_ent;
// entity hit by the line
float trace_inopen;
// boolean, true if line went through non-water area.
float trace_inwater;
// boolean, true if line went through water area.

Reply Good karma+2 votes
numbersix Author
numbersix - - 2,244 comments

Visual example of trace_plane_normal: Moddb.com

Reply Good karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: