/* ============= SV_PointContents ============= */ int SV_PointContents (vec3_t p) { edict_t *touch[MAX_EDICTS], *hit; int i, num; int contents, c2; int headnode; float *angles; // get base contents from world contents = CM_PointContents (p, sv.models[1]->headnode); // or in contents from all the other entities num = SV_AreaEdicts (p, p, touch, MAX_EDICTS, AREA_SOLID); for (i=0 ; i<num ; i++) { hit = touch[i]; // might intersect, so do an exact clip headnode = SV_HullForEntity (hit); angles = hit->s.angles; if (hit->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles); contents |= c2; } return contents; }
int SV_PointContents(const CVec3 &p) { guard(SV_PointContents); // get base contents from world unsigned contents = CM_PointContents(p, 0); contents |= CM_PointModelContents(p); edict_t *list[MAX_EDICTS]; int num = SV_AreaEdicts(p, p, ARRAY_ARG(list), AREA_SOLID); for (int i = 0; i < num; i++) { edict_t *edict = list[i]; entityHull_t &ent = ents[NUM_FOR_EDICT(edict)]; if (ent.model) contents |= CM_TransformedPointContents(p, ent.model->headnode, edict->s.origin, ent.axis); else contents |= CM_TransformedPointContents(p, CM_HeadnodeForBox(ent.bounds), edict->s.origin, nullVec3); } return contents; unguard; }
/* ==================== SV_TouchLinks ==================== */ void SV_TouchLinks ( edict_t *ent, areanode_t *node ) { int i, numtouch; edict_t *touchlist[MAX_EDICTS], *touch; int old_self, old_other; numtouch = SV_AreaEdicts (ent->v.absmin, ent->v.absmax, touchlist, MAX_EDICTS, AREA_TRIGGERS); // touch linked edicts for (i = 0; i < numtouch; i++) { touch = touchlist[i]; if (touch == ent) continue; if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) continue; old_self = pr_global_struct->self; old_other = pr_global_struct->other; pr_global_struct->self = EDICT_TO_PROG(touch); pr_global_struct->other = EDICT_TO_PROG(ent); pr_global_struct->time = sv.time; PR_ExecuteProgram (touch->v.touch); pr_global_struct->self = old_self; pr_global_struct->other = old_other; } }
/* * Call after linking a new trigger * in during gameplay to force all * entities it covers to immediately * touch it */ void G_TouchSolids(edict_t *ent) { int i, num; edict_t *touch[MAX_EDICTS], *hit; if (!ent) { return; } num = SV_AreaEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID); /* be careful, it is possible to have an entity in this list removed before we get to it (killtriggered) */ for (i = 0; i < num; i++) { hit = touch[i]; if (!hit->inuse) { continue; } if (ent->touch) { ent->touch(hit, ent, NULL, NULL); } if (!ent->inuse) { break; } } }
void G_TouchTriggers(edict_t *ent) { int i, num; edict_t *touch[MAX_EDICTS], *hit; if (!ent) { return; } /* dead things don't activate triggers! */ if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) { return; } num = SV_AreaEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); /* be careful, it is possible to have an entity in this list removed before we get to it (killtriggered) */ for (i = 0; i < num; i++) { hit = touch[i]; if (!hit->inuse) { continue; } if (!hit->touch) { continue; } hit->touch(hit, ent, NULL, NULL); } }
/* ============= SV_PointContents ============= */ int SV_PointContents(vec3_t p) { edict_t *touch[MAX_EDICTS], *hit; int i, num; int contents; if (!sv.cm.cache) { Com_Error(ERR_DROP, "%s: no map loaded", __func__); } // get base contents from world contents = CM_PointContents(p, sv.cm.cache->nodes); // or in contents from all the other entities num = SV_AreaEdicts(p, p, touch, MAX_EDICTS, AREA_SOLID); for (i = 0; i < num; i++) { hit = touch[i]; // might intersect, so do an exact clip contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit), hit->s.origin, hit->s.angles); } return contents; }
/* * ==================== SV_ClipMoveToEntities * * ==================== */ void SV_ClipMoveToEntities(moveclip_t * clip) { int i, num; edict_t *touchlist[MAX_EDICTS], *touch; trace_t trace; int headnode; float *angles; num = SV_AreaEdicts(clip->boxmins, clip->boxmaxs, touchlist ,MAX_EDICTS, AREA_SOLID); /* be careful, it is possible to have an entity in this */ /* list removed before we get to it (killtriggered) */ for (i = 0; i < num; i++) { touch = touchlist[i]; if (touch->solid == SOLID_NOT) continue; if (touch == clip->passedict) continue; if (clip->trace.allsolid) return; if (clip->passedict) { if (touch->owner == clip->passedict) continue; /* don't clip against own * missiles */ if (clip->passedict->owner == touch) continue; /* don't clip against owner */ } if (!(clip->contentmask & CONTENTS_DEADMONSTER) && (touch->svflags & SVF_DEADMONSTER)) continue; /* might intersect, so do an exact clip */ headnode = SV_HullForEntity(touch); angles = touch->s.angles; if (touch->solid != SOLID_BSP) angles = vec3_origin; /* boxes don't rotate */ if (touch->svflags & SVF_MONSTER) trace = CM_TransformedBoxTrace(clip->start, clip->end, clip->mins2, clip->maxs2, headnode, clip->contentmask, touch->s.origin, angles); else trace = CM_TransformedBoxTrace(clip->start, clip->end, clip->mins, clip->maxs, headnode, clip->contentmask, touch->s.origin, angles); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { trace.ent = touch; if (clip->trace.startsolid) { clip->trace = trace; clip->trace.startsolid = true; } else clip->trace = trace; } else if (trace.startsolid) clip->trace.startsolid = true; } }
/* ==================== SV_ClipToLinks Mins and maxs enclose the entire area swept by the move ==================== */ void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip ) { int i, numtouch; edict_t *touchlist[MAX_EDICTS], *touch; trace_t trace; numtouch = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist, MAX_EDICTS, AREA_SOLID); // touch linked edicts for (i = 0; i < numtouch; i++) { touch = touchlist[i]; if (touch == clip->passedict) continue; if (touch->v.solid == SOLID_TRIGGER) Host_Error ("Trigger in clipping list"); if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP) continue; if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) continue; // points never interact // might intersect, so do an exact clip if (clip->trace.allsolid) return; if (clip->passedict) { if (PROG_TO_EDICT(touch->v.owner) == clip->passedict) continue; // don't clip against own missiles if (PROG_TO_EDICT(clip->passedict->v.owner) == touch) continue; // don't clip against owner } if ((int)touch->v.flags & FL_MONSTER) trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end); else trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end); if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { trace.e.ent = touch; if (clip->trace.startsolid) { clip->trace = trace; clip->trace.startsolid = true; } else clip->trace = trace; } else if (trace.startsolid) clip->trace.startsolid = true; } }
/* ==================== SV_ClipMoveToEntities ==================== */ static void SV_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask, trace_t *tr) { vec3_t boxmins, boxmaxs; int i, num; edict_t *touchlist[MAX_EDICTS], *touch; trace_t trace; // create the bounding box of the entire move for (i = 0; i < 3; i++) { if (end[i] > start[i]) { boxmins[i] = start[i] + mins[i] - 1; boxmaxs[i] = end[i] + maxs[i] + 1; } else { boxmins[i] = end[i] + mins[i] - 1; boxmaxs[i] = start[i] + maxs[i] + 1; } } num = SV_AreaEdicts(boxmins, boxmaxs, touchlist, MAX_EDICTS, AREA_SOLID); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) for (i = 0; i < num; i++) { touch = touchlist[i]; if (touch->solid == SOLID_NOT) continue; if (touch == passedict) continue; if (tr->allsolid) return; if (passedict) { if (touch->owner == passedict) continue; // don't clip against own missiles if (passedict->owner == touch) continue; // don't clip against owner } if (!(contentmask & CONTENTS_DEADMONSTER) && (touch->svflags & SVF_DEADMONSTER)) continue; // might intersect, so do an exact clip CM_TransformedBoxTrace(&trace, start, end, mins, maxs, SV_HullForEntity(touch), contentmask, touch->s.origin, touch->s.angles); CM_ClipEntity(tr, &trace, touch); } }
static void SV_ClipMoveToEntities(trace_t &trace, const CVec3 &start, const CVec3 &end, const CBox &bounds, edict_t *passedict, int contentmask) { guard(SV_ClipMoveToEntities); if (trace.allsolid) return; int i; CVec3 amins, amaxs; for (i = 0; i < 3; i++) { if (start[i] < end[i]) { amins[i] = bounds.mins[i] + start[i]; amaxs[i] = bounds.maxs[i] + end[i]; } else { amins[i] = bounds.mins[i] + end[i]; amaxs[i] = bounds.maxs[i] + start[i]; } } edict_t *list[MAX_EDICTS]; int num = SV_AreaEdicts(amins, amaxs, ARRAY_ARG(list), AREA_SOLID); if (!num) return; float b1 = dot(bounds.mins, bounds.mins); float b2 = dot(bounds.maxs, bounds.maxs); float t = max(b1, b2); float traceWidth = SQRTFAST(t); CVec3 traceDir; VectorSubtract(end, start, traceDir); float traceLen = traceDir.Normalize() + traceWidth; for (i = 0; i < num; i++) { edict_t *edict = list[i]; entityHull_t &ent = ents[NUM_FOR_EDICT(edict)]; // if (!ent->linked) continue; if (edict->solid == SOLID_NOT || edict == passedict) continue; if (passedict) { if (edict->owner == passedict) continue; // don't clip against own missiles if (passedict->owner == edict) continue; // don't clip against owner } if (!(contentmask & CONTENTS_DEADMONSTER) && (edict->svflags & SVF_DEADMONSTER)) continue; CVec3 eCenter; VectorSubtract(ent.center, start, eCenter); // check position of point projection on line float entPos = dot(eCenter, traceDir); if (entPos < -traceWidth - ent.radius || entPos > traceLen + ent.radius) continue; // too near / too far // check distance between point and line CVec3 tmp; VectorMA(eCenter, -entPos, traceDir, tmp); float dist2 = dot(tmp, tmp); float dist0 = ent.radius + traceWidth; if (dist2 >= dist0 * dist0) continue; trace_t tr; if (ent.model) CM_TransformedBoxTrace(tr, start, end, bounds, ent.model->headnode, contentmask, edict->s.origin, ent.axis); else CM_TransformedBoxTrace(tr, start, end, bounds, CM_HeadnodeForBox(ent.bounds), contentmask, edict->s.origin, nullVec3); if (CM_CombineTrace(trace, tr)) trace.ent = edict; if (trace.allsolid) return; } unguard; }