rendered paste body#include "tracer.h"
/* to debug headbox using EV_RAILTRAIL (must have same defs as tracer funcs)
this shows exactly where the hax thinks the hitbox is... therefor, changes
to trace_head must also be made here
*/
void CG_RailTrail( clientInfo_t *ci, vec3_t start, vec3_t end, int type)
{
vec3_t diff, v1, v2, v3, v4, v5, v6;
if(!type) { // just a line
eth.CG_RailTrail2( ci, start, end);
return;
}
// type '1' (box)
VectorSubtract(start, end, diff);
VectorCopy(start, v1);
VectorCopy(start, v2);
VectorCopy(start, v3);
v1[0] -= diff[0];
v2[1] -= diff[1];
v3[2] -= diff[2];
eth.CG_RailTrail2( ci, start, v1);
eth.CG_RailTrail2( ci, start, v2);
eth.CG_RailTrail2( ci, start, v3);
VectorCopy(end, v4);
VectorCopy(end, v5);
VectorCopy(end, v6);
v4[0] += diff[0];
v5[1] += diff[1];
v6[2] += diff[2];
eth.CG_RailTrail2( ci, end, v4);
eth.CG_RailTrail2( ci, end, v5);
eth.CG_RailTrail2( ci, end, v6);
eth.CG_RailTrail2( ci, v2, v6);
eth.CG_RailTrail2( ci, v6, v1);
eth.CG_RailTrail2( ci, v1, v5);
eth.CG_RailTrail2( ci, v2, v4);
eth.CG_RailTrail2( ci, v4, v3);
eth.CG_RailTrail2( ci, v3, v5);
}
/* draws expected hitbox on a player */
void debug_head_box( int player )
{
vec3_t cv;
vec3_t p;
const hitbox_t *hbox;
qboolean moving;
int eFlags;
refEntity_t *head = ð.entities[player].refHead;
if( seth.value[VAR_HITBOX] == HITBOX_CUSTOM )
hbox = &custom_headhitbox;
else
hbox = &head_hitboxes[(int)seth.value[VAR_HITBOX]];
eFlags = eth.cg_entities[player].currentState->eFlags;
if( VectorCompare(eth.cg_entities[player].currentState->pos.trDelta, vec3_origin) )
moving = qfalse;
else
moving = qtrue;
if( (eFlags & EF_PRONE) || (eFlags & EF_PRONE_MOVING) )
VectorCopy( hbox->prone_offset, cv );
else {
if( !moving ){
if( eFlags & EF_CROUCHING )
VectorCopy( hbox->crouch_offset, cv );
else
VectorCopy( hbox->stand_offset, cv );
} else {
if( eFlags & EF_CROUCHING )
VectorCopy( hbox->crouch_offset_moving, cv );
else
VectorCopy( hbox->stand_offset_moving, cv );
}
}
/* rotate hitbox offset vector with tag (i guess this is so) */
VectorMA( head->origin, cv[2], head->axis[2], p );
VectorMA( p, cv[1], head->axis[1], p );
VectorMA( p, cv[0], head->axis[0], p );
vec3_t min,max;
vec3_t x,y,z;
x[0] = 1.0f; x[1] = 0.0f; x[2] = 0.0f;
y[0] = 0.0f; y[1] = 1.0f; y[2] = 0.0f;
z[0] = 0.0f; z[1] = 0.0f; z[2] = 1.0f;
VectorMA( p, -0.5* hbox->size[0], x, min );
VectorMA( min, -0.5* hbox->size[1], y, min );
VectorMA( min, -0.5* hbox->size[2], z, min );
VectorMA( p, 0.5* hbox->size[0], x, max );
VectorMA( max, 0.5* hbox->size[1], y, max );
VectorMA( max, 0.5* hbox->size[2], z, max );
//printf("hitbox on {%.1f, %.1f, %.1f}\n", p[0],p[1],p[2]);
CG_RailTrail(NULL, min, max, 1);
}
typedef struct {
vec3_t pt;
float d;
} trace_point;
int distance_test(const void *elm1, const void *elm2)
{
const trace_point *a = elm1;
const trace_point *b = elm2;
if( a->d > b->d )
return 1;
else if( a->d < b->d )
return -1;
else
return 0;
}
/* multi trace a box and return visible point
boxes have an origin, and are always world-axis aligned
Note: box is assumed to be centered on its origin
*/
qboolean trace_box( vec3_t box_origin, vec3_t size, vec3_t tr_origin, int skipent, qboolean random, qboolean multi, vec3_t visible )
{
#define MAX_TR 16
trace_t tr;
trace_point p[MAX_TR];
vec3_t x,y,z;
//trap_CM_BoxTrace( &tr, tr_origin, box_origin, NULL, NULL, 0, MASK_SHOT );
/* center trace first */
eth.CG_Trace(&tr, tr_origin, NULL,NULL, box_origin, skipent, MASK_SHOT );
/* calling trap_trace() is a lot faster, but it doesn't check for clips by movers :( */
//trap_CM_BoxTrace( &tr, tr_origin, box_origin, NULL, NULL, 0, MASK_SHOT );
if( tr.fraction == 1.f ){
VectorCopy( tr.endpos, visible );
return qtrue;
} else if( (!multi && !random) || VectorCompare(size,vec3_origin) )
return qfalse;
int k = 0;
memset(p, 0, sizeof(p));
/* Y-axis points north */
x[0] = 1.0f; x[1] = 0.0f; x[2] = 0.0f;
y[0] = 0.0f; y[1] = 1.0f; y[2] = 0.0f;
z[0] = 0.0f; z[1] = 0.0f; z[2] = 1.0f;
if( !random ){
/* trace periphery - prioritize plane centers, more chance of hitting */
VectorMA( box_origin, size[0]*0.5, x, p[k].pt ); k++;
VectorMA( box_origin, -size[0]*0.5, x, p[k].pt ); k++;
VectorMA( box_origin, size[1]*0.5, y, p[k].pt ); k++;
VectorMA( box_origin, -size[0]*0.5, y, p[k].pt ); k++;
VectorMA( box_origin, size[2]*0.5, z, p[k].pt ); k++;
/* corners */
VectorMA( box_origin, size[0]*0.5, x, p[k].pt );
VectorMA( p[k].pt, size[2]*0.5, z, p[k].pt );
k++;
VectorMA( box_origin, -size[0]*0.5, x, p[k].pt );
VectorMA( p[k].pt, size[2]*0.5, z, p[k].pt );
k++;
VectorMA( box_origin, size[1]*0.5, y, p[k].pt );
VectorMA( p[k].pt, size[2]*0.5, z, p[k].pt );
k++;
VectorMA( box_origin, -size[1]*0.5, y, p[k].pt );
VectorMA( p[k].pt, size[2]*0.5, z, p[k].pt );
k++;
} else {
/* trace random points within hbox volume */
for( k=0; k < MAX_TR; k++ ){
while( p[k].d < 0.25 ){
VectorMA( p[k].pt, size[0]*crandom()*0.5, x, p[k].pt );
VectorMA( p[k].pt, size[1]*crandom()*0.5, y, p[k].pt );
VectorMA( p[k].pt, size[2]*crandom()*0.5, z, p[k].pt );
p[k].d = VectorLengthSquared( p[k].pt );
}
}
qsort( p, MAX_TR, sizeof(trace_point), distance_test );
for( k=0; k < MAX_TR; k++ )
VectorAdd( box_origin, p[k].pt, p[k].pt );
}
/* trace them all */
for( k=0; k<MAX_TR; k++ ){
if( VectorCompare(p[k].pt, vec3_origin) )
continue;
memset( &tr, 0, sizeof(tr) );
eth.CG_Trace(&tr, tr_origin, NULL,NULL, p[k].pt, skipent, MASK_SHOT );
//trap_CM_BoxTrace( &tr, tr_origin, p[k], NULL, NULL, 0, MASK_SHOT );
if( tr.fraction == 1.f ){
VectorCopy( tr.endpos, visible );
return qtrue;
}
}
return qfalse;
}
/* build a head hitbox and trace its volume */
qboolean trace_head( refEntity_t *head, vec3_t hitpoint, int player )
{
vec3_t cv;
vec3_t p;
const hitbox_t *hbox;
qboolean moving;
int eFlags;
if( seth.value[VAR_HITBOX] == HITBOX_CUSTOM )
hbox = &custom_headhitbox;
else
hbox = &head_hitboxes[(int)seth.value[VAR_HITBOX]];
eFlags = eth.cg_entities[player].currentState->eFlags;
/* this is not really movement detector, but animation detector
only use pos.trDelta since that handles user-intended velocities */
if( VectorCompare(eth.cg_entities[player].currentState->pos.trDelta, vec3_origin) )
moving = qfalse;
else
moving = qtrue;
if( (eFlags & EF_PRONE) || (eFlags & EF_PRONE_MOVING) )
VectorCopy( hbox->prone_offset, cv );
else {
if( !moving ){
if( eFlags & EF_CROUCHING )
VectorCopy( hbox->crouch_offset, cv );
else
VectorCopy( hbox->stand_offset, cv );
} else {
if( eFlags & EF_CROUCHING )
VectorCopy( hbox->crouch_offset_moving, cv );
else
VectorCopy( hbox->stand_offset_moving, cv );
}
}
/* rotate hitbox offset vector with tag (hitboxes themselves dont rotate) */
VectorMA( head->origin, cv[2], head->axis[2], p );
VectorMA( p, cv[1], head->axis[1], p );
VectorMA( p, cv[0], head->axis[0], p );
vec3_t hit;
/* you can play a bit with the random settings... doing randomized trace gives me best results
only do complicated trace if it is enemy, if friend do simple center check
note: i suggest always do center trace first, for max acc
*/
if( trace_box( p, hbox->size, eth.muzzle, player, IS_PLAYER_ENEMY(player), qfalse, hit ) ){
VectorCopy( hit, hitpoint );
return qtrue;
} else
return qfalse;
}
/* build a body hitbox and trace it */
qboolean trace_body( int player, vec3_t hitpoint )
{
vec3_t cv;
const hitbox_t *bbox;
vec3_t size;
int eFlags;
/* for friends dont body trace, use head instead to save cpu*/
if( !IS_PLAYER_ENEMY(player) )
return eth.entities[player].isHeadVisible;
// for now just standard, maybe later extend for mod tweaking
bbox = &body_hitbox;
eFlags = eth.cg_entities[player].currentState->eFlags;
if( eFlags & EF_CROUCHING )
VectorCopy( bbox->size2, size );
else
VectorCopy( bbox->size, size );
VectorCopy( vec3_origin, cv );
vec3_t start,hit;
VectorCopy( eth.entities[player].origin, start );
VectorAdd( start, cv, start );
if( trace_box( start, size, eth.muzzle, player, qfalse, qtrue, hit ) ){
VectorCopy( hit, hitpoint );
return qtrue;
} else
return qfalse;
}