diff --git a/nq/include/server.h b/nq/include/server.h index 8dfafff4b..da80d92ed 100644 --- a/nq/include/server.h +++ b/nq/include/server.h @@ -178,6 +178,14 @@ typedef struct client_s #define FL_PARTIALGROUND 1024 // not all corners are valid #define FL_WATERJUMP 2048 // player jumping out of water #define FL_JUMPRELEASED 4096 // for jump debouncing +#define FL_FINALIZED 8192 +#define FL_FINDABLE_NONSOLID 16384 + +#define TL_ANY_SOLID 0 +#define TL_BSP_ONLY 1 +// 2 used internally (MOVE_MISSILE) +#define TL_TRIGGERS 3 // scan for triggers +#define TL_EVERYTHING 4 // scan for anything // entity effects diff --git a/nq/source/world.c b/nq/source/world.c index b301dc870..dc1652348 100644 --- a/nq/source/world.c +++ b/nq/source/world.c @@ -213,6 +213,17 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, model_t *model; vec3_t hullmins, hullmaxs, size; + if ((sv_fields.rotated_bbox != -1 + && SVinteger (ent, rotated_bbox)) + || SVfloat (ent, solid) == SOLID_BSP) { + VectorSubtract (maxs, mins, size); + if (size[0] < 3) + hull_index = 0; + else if (size[0] <= 32) + hull_index = 1; + else + hull_index = 2; + } if (sv_fields.rotated_bbox != -1 && SVinteger (ent, rotated_bbox)) { int h = SVinteger (ent, rotated_bbox) - 1; @@ -220,12 +231,18 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, } if (SVfloat (ent, solid) == SOLID_BSP) { // explicit hulls in the BSP model if (SVfloat (ent, movetype) != MOVETYPE_PUSH) - Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); + Sys_Error ("SOLID_BSP without MOVETYPE_PUSH: %d %s", + NUM_FOR_EDICT (&sv_pr_state, ent), + PR_GetString (&sv_pr_state, + SVstring (ent, classname))); model = sv.models[(int) SVfloat (ent, modelindex)]; if (!model || model->type != mod_brush) - Sys_Error ("SOLID_BSP with a non bsp model"); + Sys_Error ("SOLID_BSP with a non bsp model: %d %s", + NUM_FOR_EDICT (&sv_pr_state, ent), + PR_GetString (&sv_pr_state, + SVstring (ent, classname))); hull_list = model->hull_list; } @@ -347,8 +364,8 @@ SV_UnlinkEdict (edict_t *ent) static void SV_TouchLinks (edict_t *ent, areanode_t *node) { - edict_t *touch; int old_self, old_other; + edict_t *touch; link_t *l, *next; // touch linked edicts @@ -558,7 +575,6 @@ SV_TestEntityPosition (edict_t *ent) if (trace.startsolid) return sv.edicts; - return NULL; } @@ -569,7 +585,7 @@ SV_TestEntityPosition (edict_t *ent) eventually rotation) of the end points */ static trace_t -SV_ClipMoveToEntity (edict_t *touched, edict_t *mover, const vec3_t start, +SV_ClipMoveToEntity (edict_t *touched, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end) { hull_t *hull; @@ -605,73 +621,149 @@ SV_ClipMoveToEntity (edict_t *touched, edict_t *mover, const vec3_t start, return trace; } +static inline int +ctl_pretest_everything (edict_t *touch, moveclip_t *clip) +{ + if (touch->free) + return 0; + if (!((int) SVfloat (touch, flags) & FL_FINDABLE_NONSOLID)) { + if (SVfloat (touch, solid) == SOLID_NOT) + return 0; + if (SVfloat (touch, solid) == SOLID_TRIGGER) + return 0; + } + if (touch == clip->passedict) + return 0; + return 1; +} + +static inline int +ctl_pretest_triggers (edict_t *touch, moveclip_t *clip) +{ + if (SVfloat (touch, solid) != SOLID_TRIGGER) + return 0; + if (!((int) SVfloat (touch, flags) & FL_FINDABLE_NONSOLID)) + return 0; + if (touch == clip->passedict) + return 0; + return 1; +} + +static inline int +ctl_pretest_other (edict_t *touch, moveclip_t *clip) +{ + if (SVfloat (touch, solid) == SOLID_NOT) + return 0; + if (touch == clip->passedict) + return 0; + if (SVfloat (touch, solid) == SOLID_TRIGGER) + Sys_Error ("Trigger in clipping list"); + + if (clip->type == MOVE_NOMONSTERS && SVfloat (touch, solid) != SOLID_BSP) + return 0; + return 1; +} + +static inline int +ctl_touch_test (edict_t *touch, moveclip_t *clip) +{ + if (clip->boxmins[0] > SVvector (touch, absmax)[0] + || clip->boxmins[1] > SVvector (touch, absmax)[1] + || clip->boxmins[2] > SVvector (touch, absmax)[2] + || clip->boxmaxs[0] < SVvector (touch, absmin)[0] + || clip->boxmaxs[1] < SVvector (touch, absmin)[1] + || clip->boxmaxs[2] < SVvector (touch, absmin)[2]) + return 0; + + if (clip->passedict && SVvector (clip->passedict, size)[0] + && !SVvector (touch, size)[0]) + return 0; // points never interact + + // might intersect, so do an exact clip + if (clip->passedict) { + if (PROG_TO_EDICT (&sv_pr_state, SVentity (touch, owner)) + == clip->passedict) + return 0; // don't clip against own missiles + if (PROG_TO_EDICT (&sv_pr_state, + SVentity (clip->passedict, owner)) == touch) + return 0; // don't clip against owner + } + return 1; +} + +static void +ctl_do_clip (edict_t *touch, moveclip_t *clip, trace_t *trace) +{ + if ((int) SVfloat (touch, 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->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 */ static void -SV_ClipToLinks (areanode_t *node, moveclip_t * clip) +SV_ClipToLinks (areanode_t *node, moveclip_t *clip) { edict_t *touch; link_t *l, *next; trace_t trace; + int i; - // touch linked edicts - for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { - next = l->next; - touch = EDICT_FROM_AREA (l); - if (SVfloat (touch, solid) == SOLID_NOT) - continue; - if (touch == clip->passedict) - continue; - if (SVfloat (touch, solid) == SOLID_TRIGGER) - Sys_Error ("Trigger in clipping list"); - - if (clip->type == MOVE_NOMONSTERS - && SVfloat (touch, solid) != SOLID_BSP) - continue; - - if (clip->boxmins[0] > SVvector (touch, absmax)[0] - || clip->boxmins[1] > SVvector (touch, absmax)[1] - || clip->boxmins[2] > SVvector (touch, absmax)[2] - || clip->boxmaxs[0] < SVvector (touch, absmin)[0] - || clip->boxmaxs[1] < SVvector (touch, absmin)[1] - || clip->boxmaxs[2] < SVvector (touch, absmin)[2]) - continue; - - if (clip->passedict != 0 && SVvector (clip->passedict, size)[0] - && !SVvector (touch, 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 (&sv_pr_state, SVentity (touch, owner)) - == clip->passedict) - continue; // don't clip against own missiles - if (PROG_TO_EDICT (&sv_pr_state, - SVentity (clip->passedict, owner)) == touch) - continue; // don't clip against owner + if (clip->type == TL_EVERYTHING) { + touch = NEXT_EDICT (&sv_pr_state, sv.edicts); + for (i = 1; i < sv.num_edicts; i++, + touch = NEXT_EDICT (&sv_pr_state, touch)) { + if (clip->trace.allsolid) + return; + if (!ctl_pretest_everything (touch, clip)) + continue; + if (!ctl_touch_test (touch, clip)) + continue; + ctl_do_clip (touch, clip, &trace); } + } else if (clip->type == TL_TRIGGERS) { + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { + next = l->next; + touch = EDICT_FROM_AREA (l); - if ((int) SVfloat (touch, flags) & FL_MONSTER) - trace = SV_ClipMoveToEntity (touch, clip->passedict, clip->start, - clip->mins2, clip->maxs2, clip->end); - else - trace = SV_ClipMoveToEntity (touch, clip->passedict, clip->start, - clip->mins, clip->maxs, clip->end); - 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; + if (clip->trace.allsolid) + return; + if (!ctl_pretest_triggers (touch, clip)) + continue; + if (!ctl_touch_test (touch, clip)) + continue; + ctl_do_clip (touch, clip, &trace); + } + } else { + // touch linked edicts + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { + next = l->next; + touch = EDICT_FROM_AREA (l); + + if (clip->trace.allsolid) + return; + if (!ctl_pretest_other (touch, clip)) + continue; + if (!ctl_touch_test (touch, clip)) + continue; + ctl_do_clip (touch, clip, &trace); + } } // recurse down both sides @@ -717,8 +809,7 @@ SV_Move (const vec3_t start, const vec3_t mins, const vec3_t maxs, memset (&clip, 0, sizeof (moveclip_t)); // clip to world - clip.trace = SV_ClipMoveToEntity (sv.edicts, passedict, start, - mins, maxs, end); + clip.trace = SV_ClipMoveToEntity (sv.edicts, start, mins, maxs, end); clip.start = start; clip.end = end; clip.mins = mins; diff --git a/qw/source/world.c b/qw/source/world.c index 552957cde..dc1652348 100644 --- a/qw/source/world.c +++ b/qw/source/world.c @@ -28,7 +28,7 @@ # include "config.h" #endif -static __attribute__ ((used)) const char rcsid[] = +static __attribute__ ((used)) const char rcsid[] = "$Id$"; #ifdef HAVE_STRING_H @@ -129,7 +129,7 @@ typedef struct { const float *start, *end; trace_t trace; int type; - edict_t *passedict; + edict_t *passedict; } moveclip_t; /* HULL BOXES */ @@ -208,10 +208,10 @@ hull_t * SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, vec3_t extents, vec3_t offset) { - hull_t *hull = 0; int hull_index = 0; + hull_t *hull = 0, **hull_list = 0; model_t *model; - vec3_t hullmins, hullmaxs, size; + vec3_t hullmins, hullmaxs, size; if ((sv_fields.rotated_bbox != -1 && SVinteger (ent, rotated_bbox)) @@ -224,11 +224,10 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, else hull_index = 2; } - // decide which clipping hull to use, based on the size if (sv_fields.rotated_bbox != -1 && SVinteger (ent, rotated_bbox)) { int h = SVinteger (ent, rotated_bbox) - 1; - hull = pf_hull_list[h]->hulls[hull_index]; + hull_list = pf_hull_list[h]->hulls; } if (SVfloat (ent, solid) == SOLID_BSP) { // explicit hulls in the BSP model if (SVfloat (ent, movetype) != MOVETYPE_PUSH) @@ -245,19 +244,49 @@ SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs, PR_GetString (&sv_pr_state, SVstring (ent, classname))); - hull = &model->hulls[hull_index]; + hull_list = model->hull_list; + } + if (hull_list) { + // decide which clipping hull to use, based on the size + VectorSubtract (maxs, mins, size); + if (extents) { + VectorScale (size, 0.5, extents); + } else { + if (size[0] < 3) + hull_index = 0; + else if (size[0] <= 32) + hull_index = 1; + else + hull_index = 2; + } + hull = hull_list[hull_index]; } if (hull) { // calculate an offset value to center the origin - VectorSubtract (hull->clip_mins, mins, offset); - VectorAdd (offset, SVvector (ent, origin), offset); - } else { // create a temp hull from bounding box sizes - VectorSubtract (SVvector (ent, mins), maxs, hullmins); - VectorSubtract (SVvector (ent, maxs), mins, hullmaxs); - hull = SV_HullForBox (hullmins, hullmaxs); + if (extents) { + VectorAdd (extents, mins, offset); + VectorSubtract (SVvector (ent, origin), offset, offset); + } else { + VectorSubtract (hull->clip_mins, mins, offset); + VectorAdd (offset, SVvector (ent, origin), offset); + } + } else { + // create a temp hull from bounding box sizes + if (extents) { + VectorCopy (SVvector (ent, mins), hullmins); + VectorCopy (SVvector (ent, maxs), hullmaxs); - VectorCopy (SVvector (ent, origin), offset); + //FIXME broken for map models (ie, origin always 0, 0, 0) + VectorAdd (extents, mins, offset); + VectorSubtract (SVvector (ent, origin), offset, offset); + } else { + VectorSubtract (SVvector (ent, mins), maxs, hullmins); + VectorSubtract (SVvector (ent, maxs), mins, hullmaxs); + + VectorCopy (SVvector (ent, origin), offset); + } + hull = SV_HullForBox (hullmins, hullmaxs); } return hull; @@ -568,10 +597,12 @@ SV_ClipMoveToEntity (edict_t *touched, const vec3_t start, trace.fraction = 1; trace.allsolid = true; + trace.isbox = 0; VectorCopy (end, trace.endpos); // get the clipping hull - hull = SV_HullForEntity (touched, mins, maxs, 0, offset); + hull = SV_HullForEntity (touched, mins, maxs, + trace.isbox ? trace.extents : 0, offset); VectorSubtract (start, offset, start_l); VectorSubtract (end, offset, end_l); @@ -690,7 +721,7 @@ static void SV_ClipToLinks (areanode_t *node, moveclip_t *clip) { edict_t *touch; - link_t *l; + link_t *l, *next; trace_t trace; int i; @@ -707,8 +738,8 @@ SV_ClipToLinks (areanode_t *node, moveclip_t *clip) ctl_do_clip (touch, clip, &trace); } } else if (clip->type == TL_TRIGGERS) { - for (l = node->solid_edicts.next; - l != &node->solid_edicts; l = l->next) { + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { + next = l->next; touch = EDICT_FROM_AREA (l); if (clip->trace.allsolid) @@ -721,8 +752,8 @@ SV_ClipToLinks (areanode_t *node, moveclip_t *clip) } } else { // touch linked edicts - for (l = node->solid_edicts.next; - l != &node->solid_edicts; l = l->next) { + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) { + next = l->next; touch = EDICT_FROM_AREA (l); if (clip->trace.allsolid) @@ -745,7 +776,7 @@ SV_ClipToLinks (areanode_t *node, moveclip_t *clip) SV_ClipToLinks (node->children[1], clip); } -static void +static inline void SV_MoveBounds (const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs) { @@ -778,9 +809,7 @@ SV_Move (const vec3_t start, const vec3_t mins, const vec3_t maxs, memset (&clip, 0, sizeof (moveclip_t)); // clip to world - clip.trace = SV_ClipMoveToEntity (sv.edicts, start, - mins, maxs, end); - + clip.trace = SV_ClipMoveToEntity (sv.edicts, start, mins, maxs, end); clip.start = start; clip.end = end; clip.mins = mins; @@ -811,9 +840,9 @@ SV_Move (const vec3_t start, const vec3_t mins, const vec3_t maxs, edict_t * SV_TestPlayerPosition (edict_t *ent, const vec3_t origin) { + int e; edict_t *check; hull_t *hull; - int e; vec3_t boxmins, boxmaxs, offset; // check world first