/* * GClip_SetBrushModel * * Also sets mins and maxs for inline bmodels */ void GClip_SetBrushModel( edict_t *ent, char *name ) { struct cmodel_s *cmodel; if( !name ) { //racesow G_Printf( "Warning: GClip_SetBrushModel: NULL model in '%s'", ent->classname ? ent->classname : "no classname\n" ); GClip_UnlinkEntity( ent ); G_FreeEdict( ent ); return; //!racesow } if( !name[0] ) { ent->s.modelindex = 0; return; } if( name[0] != '*' ) { ent->s.modelindex = trap_ModelIndex( name ); return; } // if it is an inline model, get the size information for it // world model is special if( !strcmp( name, "*0" ) ) { ent->s.modelindex = 0; cmodel = trap_CM_InlineModel( 0 ); trap_CM_InlineModelBounds( cmodel, ent->r.mins, ent->r.maxs ); return; } // racesow: THIS IS A VERY DIRTY "FIX": it assigns normally unreachable models (the ones over MAX_MODELS) to unrelated models.. // normally this only affects buggy maps that otherwise wouldn't load (like amt-freestyle3) // brush model //ent->s.modelindex = trap_ModelIndex( name ); // <- This is the unmodified version ent->s.modelindex = atoi( name+1 ); // !racesow assert( ent->s.modelindex == (unsigned int)atoi( name + 1 ) ); cmodel = trap_CM_InlineModel( ent->s.modelindex ); trap_CM_InlineModelBounds( cmodel, ent->r.mins, ent->r.maxs ); GClip_LinkEntity( ent ); }
/* ================ CG_PointContents ================ */ int CG_PointContents( const vec3_t point, int passEntityNum ) { int i; entityState_t *ent; centity_t *cent; clipHandle_t cmodel; int contents; contents = trap_CM_PointContents (point, 0); for ( i = 0 ; i < cg_numSolidEntities ; i++ ) { cent = cg_solidEntities[ i ]; ent = ¢->currentState; if ( ent->number == passEntityNum ) { continue; } if ( ent->collisionType != CT_SUBMODEL ) { continue; } cmodel = trap_CM_InlineModel( ent->modelindex ); if ( !cmodel ) { continue; } contents |= trap_CM_TransformedPointContents( point, cmodel, cent->lerpOrigin, cent->lerpAngles ); } return contents; }
/* * GClip_SetBrushModel * * Also sets mins and maxs for inline bmodels */ void GClip_SetBrushModel( edict_t *ent, const char *name ) { struct cmodel_s *cmodel; if( !name ) { G_Error( "GClip_SetBrushModel: NULL model in '%s'", ent->classname ? ent->classname : "no classname" ); // racesow GClip_UnlinkEntity( ent ); G_FreeEdict( ent ); return; // !racesow } if( !name[0] ) { ent->s.modelindex = 0; return; } if( name[0] != '*' ) { ent->s.modelindex = trap_ModelIndex( name ); return; } // if it is an inline model, get the size information for it // world model is special if( !strcmp( name, "*0" ) ) { ent->s.modelindex = 0; cmodel = trap_CM_InlineModel( 0 ); trap_CM_InlineModelBounds( cmodel, ent->r.mins, ent->r.maxs ); return; } // brush model ent->s.modelindex = trap_ModelIndex( name ); assert( ent->s.modelindex == (unsigned int)atoi( name + 1 ) ); cmodel = trap_CM_InlineModel( ent->s.modelindex ); trap_CM_InlineModelBounds( cmodel, ent->r.mins, ent->r.maxs ); GClip_LinkEntity( ent ); }
/* * GClip_ClearWorld * called after the world model has been loaded, before linking any entities */ void GClip_ClearWorld( void ) { vec3_t world_mins, world_maxs; struct cmodel_s *world_model; world_model = trap_CM_InlineModel( 0 ); trap_CM_InlineModelBounds( world_model, world_mins, world_maxs ); GClip_Init_AreaGrid( &g_areagrid, world_mins, world_maxs ); }
/* * GClip_ClearWorld * called after the world model has been loaded, before linking any entities */ void GClip_ClearWorld( void ) { vec3_t mins, maxs; struct cmodel_s *cmodel; memset( sv_areanodes, 0, sizeof( sv_areanodes ) ); sv_numareanodes = 0; cmodel = trap_CM_InlineModel( 0 ); trap_CM_InlineModelBounds( cmodel, mins, maxs ); GClip_CreateAreaNode( 0, mins, maxs ); }
/* * GClip_CollisionModelForEntity * * Returns a collision model that can be used for testing or clipping an * object of mins/maxs size. */ static struct cmodel_s *GClip_CollisionModelForEntity( entity_state_t *s, entity_shared_t *r ) { struct cmodel_s *model; if( ISBRUSHMODEL( s->modelindex ) ) { // explicit hulls in the BSP model model = trap_CM_InlineModel( s->modelindex ); if( !model ) G_Error( "MOVETYPE_PUSH with a non bsp model" ); return model; } // create a temp hull from bounding box sizes if( s->type == ET_PLAYER || s->type == ET_CORPSE ) return trap_CM_OctagonModelForBBox( r->mins, r->maxs ); else return trap_CM_ModelForBBox( r->mins, r->maxs ); }
/* * GClip_EntityContact */ static qboolean GClip_EntityContact( vec3_t mins, vec3_t maxs, edict_t *ent ) { trace_t tr; struct cmodel_s *model; if( !mins ) mins = vec3_origin; if( !maxs ) maxs = vec3_origin; if( ISBRUSHMODEL( ent->s.modelindex ) ) { model = trap_CM_InlineModel( ent->s.modelindex ); if( !model ) G_Error( "MOVETYPE_PUSH with a non bsp model" ); trap_CM_TransformedBoxTrace( &tr, vec3_origin, vec3_origin, mins, maxs, model, MASK_ALL, ent->s.origin, ent->s.angles ); return tr.startsolid || tr.allsolid; } return ( BoundsIntersect( mins, maxs, ent->r.absmin, ent->r.absmax ) ); }
/* ========================= CG_TouchTriggerPrediction Predict push triggers and items ========================= */ static void CG_TouchTriggerPrediction( void ) { int i; trace_t trace; entityState_t *ent; clipHandle_t cmodel; centity_t *cent; qboolean spectator; // dead players don't activate triggers if ( cg.cur_lc->predictedPlayerState.stats[STAT_HEALTH] <= 0 ) { return; } spectator = ( cg.cur_lc->predictedPlayerState.pm_type == PM_SPECTATOR ); if ( cg.cur_lc->predictedPlayerState.pm_type != PM_NORMAL && !spectator ) { return; } for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) { cent = cg_triggerEntities[ i ]; ent = ¢->currentState; if ( ent->eType == ET_ITEM && !spectator ) { CG_TouchItem( cent ); continue; } if ( ent->collisionType != CT_SUBMODEL ) { continue; } cmodel = trap_CM_InlineModel( ent->modelindex ); if ( !cmodel ) { continue; } if ( cg.cur_lc->predictedPlayerState.collisionType == CT_CAPSULE ) { trap_CM_CapsuleTrace( &trace, cg.cur_lc->predictedPlayerState.origin, cg.cur_lc->predictedPlayerState.origin, cg.cur_lc->predictedPlayerState.mins, cg.cur_lc->predictedPlayerState.maxs, cmodel, -1 ); } else { trap_CM_BoxTrace( &trace, cg.cur_lc->predictedPlayerState.origin, cg.cur_lc->predictedPlayerState.origin, cg.cur_lc->predictedPlayerState.mins, cg.cur_lc->predictedPlayerState.maxs, cmodel, -1 ); } if ( !trace.startsolid ) { continue; } if ( ent->eType == ET_TELEPORT_TRIGGER ) { cg.cur_lc->hyperspace = qtrue; } else if ( ent->eType == ET_PUSH_TRIGGER ) { BG_TouchJumpPad( &cg.cur_lc->predictedPlayerState, ent ); } } // if we didn't touch a jump pad this pmove frame if ( cg.cur_lc->predictedPlayerState.jumppad_frame != cg.cur_lc->predictedPlayerState.pmove_framecount ) { cg.cur_lc->predictedPlayerState.jumppad_frame = 0; cg.cur_lc->predictedPlayerState.jumppad_ent = 0; } }
/* ==================== CG_ClipMoveToEntities ==================== */ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int skipNumber, int mask, trace_t *tr, traceType_t traceType ) { int i; trace_t trace; entityState_t *ent; clipHandle_t cmodel; vec3_t origin, angles; centity_t *cent; for ( i = 0 ; i < cg_numSolidEntities ; i++ ) { cent = cg_solidEntities[ i ]; ent = ¢->currentState; if ( ent->number == skipNumber ) { continue; } // if it doesn't have any brushes of a type we // are looking for, ignore it if ( !(mask & ent->contents) ) { continue; } if ( ent->collisionType == CT_SUBMODEL ) { cmodel = trap_CM_InlineModel( ent->modelindex ); VectorCopy( cent->lerpAngles, angles ); BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin ); } else if ( ent->collisionType == CT_CAPSULE ) { cmodel = trap_CM_TempCapsuleModel( ent->mins, ent->maxs, ent->contents ); VectorCopy( vec3_origin, angles ); VectorCopy( cent->lerpOrigin, origin ); } else /* if ( ent->collisionType == CT_AABB ) */ { cmodel = trap_CM_TempBoxModel( ent->mins, ent->maxs, ent->contents ); VectorCopy( vec3_origin, angles ); VectorCopy( cent->lerpOrigin, origin ); } if ( traceType == TT_BISPHERE ) { trap_CM_TransformedBiSphereTrace( &trace, start, end, mins[ 0 ], maxs[ 0 ], cmodel, mask, origin ); } else if ( traceType == TT_CAPSULE ) { trap_CM_TransformedCapsuleTrace ( &trace, start, end, mins, maxs, cmodel, mask, origin, angles ); } else /* if ( traceType == TT_AABB ) */ { trap_CM_TransformedBoxTrace ( &trace, start, end, mins, maxs, cmodel, mask, origin, angles ); } if (trace.allsolid || trace.fraction < tr->fraction) { trace.entityNum = ent->number; if( tr->lateralFraction < trace.lateralFraction ) { float oldLateralFraction = tr->lateralFraction; *tr = trace; tr->lateralFraction = oldLateralFraction; } else { *tr = trace; } } else if (trace.startsolid) { tr->startsolid = qtrue; tr->entityNum = ent->number; } if ( tr->allsolid ) { return; } } }