1 /* 2 Copyright (C) 1996-1997 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // world.c -- world query functions 21 22 #include "quakedef.h" 23 24 /* 25 26 entities never clip against themselves, or their owner 27 28 line of sight checks trace->crosscontent, but bullets don't 29 30 */ 31 32 33 typedef struct 34 { 35 vec3_t boxmins, boxmaxs;// enclose the test object along entire move 36 float *mins, *maxs; // size of the moving object 37 vec3_t mins2, maxs2; // size when clipping against mosnters 38 float *start, *end; 39 trace_t trace; 40 int type; 41 edict_t *passedict; 42 } moveclip_t; 43 44 45 int SV_HullPointContents (hull_t *hull, int num, vec3_t p); 46 47 /* 48 =============================================================================== 49 50 HULL BOXES 51 52 =============================================================================== 53 */ 54 55 56 static hull_t box_hull; 57 static dclipnode_t box_clipnodes[6]; 58 static mplane_t box_planes[6]; 59 60 /* 61 =================== 62 SV_InitBoxHull 63 64 Set up the planes and clipnodes so that the six floats of a bounding box 65 can just be stored out and get a proper hull_t structure. 66 =================== 67 */ 68 void SV_InitBoxHull (void) 69 { 70 int i; 71 int side; 72 73 box_hull.clipnodes = box_clipnodes; 74 box_hull.planes = box_planes; 75 box_hull.firstclipnode = 0; 76 box_hull.lastclipnode = 5; 77 78 for (i=0 ; i<6 ; i++) 79 { 80 box_clipnodes[i].planenum = i; 81 82 side = i&1; 83 84 box_clipnodes[i].children[side] = CONTENTS_EMPTY; 85 if (i != 5) 86 box_clipnodes[i].children[side^1] = i + 1; 87 else 88 box_clipnodes[i].children[side^1] = CONTENTS_SOLID; 89 90 box_planes[i].type = i>>1; 91 box_planes[i].normal[i>>1] = 1; 92 } 93 94 } 95 96 97 /* 98 =================== 99 SV_HullForBox 100 101 To keep everything totally uniform, bounding boxes are turned into small 102 BSP trees instead of being compared directly. 103 =================== 104 */ 105 hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs) 106 { 107 box_planes[0].dist = maxs[0]; 108 box_planes[1].dist = mins[0]; 109 box_planes[2].dist = maxs[1]; 110 box_planes[3].dist = mins[1]; 111 box_planes[4].dist = maxs[2]; 112 box_planes[5].dist = mins[2]; 113 114 return &box_hull; 115 } 116 117 118 119 /* 120 ================ 121 SV_HullForEntity 122 123 Returns a hull that can be used for testing or clipping an object of mins/maxs 124 size. 125 Offset is filled in to contain the adjustment that must be added to the 126 testing object's origin to get a point to use with the returned hull. 127 ================ 128 */ 129 hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) 130 { 131 model_t *model; 132 vec3_t size; 133 vec3_t hullmins, hullmaxs; 134 hull_t *hull; 135 136 // decide which clipping hull to use, based on the size 137 if (ent->u.v.solid == SOLID_BSP) 138 { // explicit hulls in the BSP model 139 if (ent->u.v.movetype != MOVETYPE_PUSH) 140 Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); 141 142 model = sv.models[ (int)ent->u.v.modelindex ]; 143 144 if (!model || model->type != mod_brush) 145 Sys_Error ("MOVETYPE_PUSH with a non bsp model"); 146 147 VectorSubtract (maxs, mins, size); 148 if (size[0] < 3) 149 hull = &model->hulls[0]; 150 else if (size[0] <= 32) 151 hull = &model->hulls[1]; 152 else 153 hull = &model->hulls[2]; 154 155 // calculate an offset value to center the origin 156 VectorSubtract (hull->clip_mins, mins, offset); 157 VectorAdd (offset, ent->u.v.origin, offset); 158 } 159 else 160 { // create a temp hull from bounding box sizes 161 162 VectorSubtract (ent->u.v.mins, maxs, hullmins); 163 VectorSubtract (ent->u.v.maxs, mins, hullmaxs); 164 hull = SV_HullForBox (hullmins, hullmaxs); 165 166 VectorCopy (ent->u.v.origin, offset); 167 } 168 169 170 return hull; 171 } 172 173 /* 174 =============================================================================== 175 176 ENTITY AREA CHECKING 177 178 =============================================================================== 179 */ 180 181 typedef struct areanode_s 182 { 183 int axis; // -1 = leaf node 184 float dist; 185 struct areanode_s *children[2]; 186 link_t trigger_edicts; 187 link_t solid_edicts; 188 } areanode_t; 189 190 #define AREA_DEPTH 4 191 #define AREA_NODES 32 192 193 static areanode_t sv_areanodes[AREA_NODES]; 194 static int sv_numareanodes; 195 196 /* 197 =============== 198 SV_CreateAreaNode 199 200 =============== 201 */ 202 areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) 203 { 204 areanode_t *anode; 205 vec3_t size; 206 vec3_t mins1, maxs1, mins2, maxs2; 207 208 anode = &sv_areanodes[sv_numareanodes]; 209 sv_numareanodes++; 210 211 ClearLink (&anode->trigger_edicts); 212 ClearLink (&anode->solid_edicts); 213 214 if (depth == AREA_DEPTH) 215 { 216 anode->axis = -1; 217 anode->children[0] = anode->children[1] = NULL; 218 return anode; 219 } 220 221 VectorSubtract (maxs, mins, size); 222 if (size[0] > size[1]) 223 anode->axis = 0; 224 else 225 anode->axis = 1; 226 227 anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); 228 VectorCopy (mins, mins1); 229 VectorCopy (mins, mins2); 230 VectorCopy (maxs, maxs1); 231 VectorCopy (maxs, maxs2); 232 233 maxs1[anode->axis] = mins2[anode->axis] = anode->dist; 234 235 anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2); 236 anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); 237 238 return anode; 239 } 240 241 /* 242 =============== 243 SV_ClearWorld 244 245 =============== 246 */ 247 void SV_ClearWorld (void) 248 { 249 SV_InitBoxHull (); 250 251 memset (sv_areanodes, 0, sizeof(sv_areanodes)); 252 sv_numareanodes = 0; 253 SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs); 254 } 255 256 257 /* 258 =============== 259 SV_UnlinkEdict 260 261 =============== 262 */ 263 void SV_UnlinkEdict (edict_t *ent) 264 { 265 if (!ent->area.prev) 266 return; // not linked in anywhere 267 RemoveLink (&ent->area); 268 ent->area.prev = ent->area.next = NULL; 269 } 270 271 272 /* 273 ==================== 274 SV_TouchLinks 275 ==================== 276 */ 277 void SV_TouchLinks ( edict_t *ent, areanode_t *node ) 278 { 279 link_t *l, *next; 280 edict_t *touch; 281 int old_self, old_other; 282 283 // touch linked edicts 284 for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next) 285 { 286 next = l->next; 287 touch = EDICT_FROM_AREA(l); 288 if (touch == ent) 289 continue; 290 if (!touch->u.v.touch || touch->u.v.solid != SOLID_TRIGGER) 291 continue; 292 if (ent->u.v.absmin[0] > touch->u.v.absmax[0] 293 || ent->u.v.absmin[1] > touch->u.v.absmax[1] 294 || ent->u.v.absmin[2] > touch->u.v.absmax[2] 295 || ent->u.v.absmax[0] < touch->u.v.absmin[0] 296 || ent->u.v.absmax[1] < touch->u.v.absmin[1] 297 || ent->u.v.absmax[2] < touch->u.v.absmin[2] ) 298 continue; 299 old_self = pr_global_struct->self; 300 old_other = pr_global_struct->other; 301 302 pr_global_struct->self = EDICT_TO_PROG(touch); 303 pr_global_struct->other = EDICT_TO_PROG(ent); 304 pr_global_struct->time = sv.time; 305 PR_ExecuteProgram (touch->u.v.touch); 306 307 pr_global_struct->self = old_self; 308 pr_global_struct->other = old_other; 309 } 310 311 // recurse down both sides 312 if (node->axis == -1) 313 return; 314 315 if ( ent->u.v.absmax[node->axis] > node->dist ) 316 SV_TouchLinks ( ent, node->children[0] ); 317 if ( ent->u.v.absmin[node->axis] < node->dist ) 318 SV_TouchLinks ( ent, node->children[1] ); 319 } 320 321 322 /* 323 =============== 324 SV_FindTouchedLeafs 325 326 =============== 327 */ 328 void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) 329 { 330 mplane_t *splitplane; 331 mleaf_t *leaf; 332 int sides; 333 int leafnum; 334 335 if (node->contents == CONTENTS_SOLID) 336 return; 337 338 // add an efrag if the node is a leaf 339 340 if ( node->contents < 0) 341 { 342 if (ent->num_leafs == MAX_ENT_LEAFS) 343 return; 344 345 leaf = (mleaf_t *)node; 346 leafnum = leaf - sv.worldmodel->leafs - 1; 347 348 ent->leafnums[ent->num_leafs] = leafnum; 349 ent->num_leafs++; 350 return; 351 } 352 353 // NODE_MIXED 354 355 splitplane = node->plane; 356 sides = BOX_ON_PLANE_SIDE(ent->u.v.absmin, ent->u.v.absmax, splitplane); 357 358 // recurse down the contacted sides 359 if (sides & 1) 360 SV_FindTouchedLeafs (ent, node->children[0]); 361 362 if (sides & 2) 363 SV_FindTouchedLeafs (ent, node->children[1]); 364 } 365 366 /* 367 =============== 368 SV_LinkEdict 369 370 =============== 371 */ 372 void SV_LinkEdict (edict_t *ent, qboolean touch_triggers) 373 { 374 areanode_t *node; 375 376 if (ent->area.prev) 377 SV_UnlinkEdict (ent); // unlink from old position 378 379 if (ent == sv.edicts) 380 return; // don't add the world 381 382 if (ent->free) 383 return; 384 385 // set the abs box 386 387 #ifdef QUAKE2 388 if (ent->u.v.solid == SOLID_BSP && 389 (ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) ) 390 { // expand for rotation 391 float max, v; 392 int i; 393 394 max = 0; 395 for (i=0 ; i<3 ; i++) 396 { 397 v =fabs( ent->u.v.mins[i]); 398 if (v > max) 399 max = v; 400 v =fabs( ent->u.v.maxs[i]); 401 if (v > max) 402 max = v; 403 } 404 for (i=0 ; i<3 ; i++) 405 { 406 ent->u.v.absmin[i] = ent->u.v.origin[i] - max; 407 ent->u.v.absmax[i] = ent->u.v.origin[i] + max; 408 } 409 } 410 else 411 #endif 412 { 413 VectorAdd (ent->u.v.origin, ent->u.v.mins, ent->u.v.absmin); 414 VectorAdd (ent->u.v.origin, ent->u.v.maxs, ent->u.v.absmax); 415 } 416 417 // 418 // to make items easier to pick up and allow them to be grabbed off 419 // of shelves, the abs sizes are expanded 420 // 421 if ((int)ent->u.v.flags & FL_ITEM) 422 { 423 ent->u.v.absmin[0] -= 15; 424 ent->u.v.absmin[1] -= 15; 425 ent->u.v.absmax[0] += 15; 426 ent->u.v.absmax[1] += 15; 427 } 428 else 429 { // because movement is clipped an epsilon away from an actual edge, 430 // we must fully check even when bounding boxes don't quite touch 431 ent->u.v.absmin[0] -= 1; 432 ent->u.v.absmin[1] -= 1; 433 ent->u.v.absmin[2] -= 1; 434 ent->u.v.absmax[0] += 1; 435 ent->u.v.absmax[1] += 1; 436 ent->u.v.absmax[2] += 1; 437 } 438 439 // link to PVS leafs 440 ent->num_leafs = 0; 441 if (ent->u.v.modelindex) 442 SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); 443 444 if (ent->u.v.solid == SOLID_NOT) 445 return; 446 447 // find the first node that the ent's box crosses 448 node = sv_areanodes; 449 while (1) 450 { 451 if (node->axis == -1) 452 break; 453 if (ent->u.v.absmin[node->axis] > node->dist) 454 node = node->children[0]; 455 else if (ent->u.v.absmax[node->axis] < node->dist) 456 node = node->children[1]; 457 else 458 break; // crosses the node 459 } 460 461 // link it in 462 463 if (ent->u.v.solid == SOLID_TRIGGER) 464 InsertLinkBefore (&ent->area, &node->trigger_edicts); 465 else 466 InsertLinkBefore (&ent->area, &node->solid_edicts); 467 468 // if touch_triggers, touch all entities at this node and decend for more 469 if (touch_triggers) 470 SV_TouchLinks ( ent, sv_areanodes ); 471 } 472 473 474 475 /* 476 =============================================================================== 477 478 POINT TESTING IN HULLS 479 480 =============================================================================== 481 */ 482 483 #if !id386 484 485 /* 486 ================== 487 SV_HullPointContents 488 489 ================== 490 */ 491 int SV_HullPointContents (hull_t *hull, int num, vec3_t p) 492 { 493 float d; 494 dclipnode_t *node; 495 mplane_t *plane; 496 497 while (num >= 0) 498 { 499 if (num < hull->firstclipnode || num > hull->lastclipnode) 500 Sys_Error ("SV_HullPointContents: bad node number"); 501 502 node = hull->clipnodes + num; 503 plane = hull->planes + node->planenum; 504 505 if (plane->type < 3) 506 d = p[plane->type] - plane->dist; 507 else 508 d = DotProduct (plane->normal, p) - plane->dist; 509 if (d < 0) 510 num = node->children[1]; 511 else 512 num = node->children[0]; 513 } 514 515 return num; 516 } 517 518 #endif // !id386 519 520 521 /* 522 ================== 523 SV_PointContents 524 525 ================== 526 */ 527 int SV_PointContents (vec3_t p) 528 { 529 int cont; 530 531 cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); 532 if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) 533 cont = CONTENTS_WATER; 534 return cont; 535 } 536 537 int SV_TruePointContents (vec3_t p) 538 { 539 return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); 540 } 541 542 //=========================================================================== 543 544 /* 545 ============ 546 SV_TestEntityPosition 547 548 This could be a lot more efficient... 549 ============ 550 */ 551 edict_t *SV_TestEntityPosition (edict_t *ent) 552 { 553 trace_t trace; 554 555 trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, ent->u.v.origin, 0, ent); 556 557 if (trace.startsolid) 558 return sv.edicts; 559 560 return NULL; 561 } 562 563 564 /* 565 =============================================================================== 566 567 LINE TESTING IN HULLS 568 569 =============================================================================== 570 */ 571 572 // 1/32 epsilon to keep floating point happy 573 #define DIST_EPSILON (0.03125) 574 575 /* 576 ================== 577 SV_RecursiveHullCheck 578 579 ================== 580 */ 581 qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) 582 { 583 dclipnode_t *node; 584 mplane_t *plane; 585 float t1, t2; 586 float frac; 587 int i; 588 vec3_t mid; 589 int side; 590 float midf; 591 592 // check for empty 593 if (num < 0) 594 { 595 if (num != CONTENTS_SOLID) 596 { 597 trace->allsolid = false; 598 if (num == CONTENTS_EMPTY) 599 trace->inopen = true; 600 else 601 trace->inwater = true; 602 } 603 else 604 trace->startsolid = true; 605 return true; // empty 606 } 607 608 if (num < hull->firstclipnode || num > hull->lastclipnode) 609 Sys_Error ("SV_RecursiveHullCheck: bad node number"); 610 611 // 612 // find the point distances 613 // 614 node = hull->clipnodes + num; 615 plane = hull->planes + node->planenum; 616 617 if (plane->type < 3) 618 { 619 t1 = p1[plane->type] - plane->dist; 620 t2 = p2[plane->type] - plane->dist; 621 } 622 else 623 { 624 t1 = DotProduct (plane->normal, p1) - plane->dist; 625 t2 = DotProduct (plane->normal, p2) - plane->dist; 626 } 627 628 #if 1 629 if (t1 >= 0 && t2 >= 0) 630 return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); 631 if (t1 < 0 && t2 < 0) 632 return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); 633 #else 634 if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) 635 return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); 636 if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) 637 return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); 638 #endif 639 640 // put the crosspoint DIST_EPSILON pixels on the near side 641 if (t1 < 0) 642 frac = (t1 + DIST_EPSILON)/(t1-t2); 643 else 644 frac = (t1 - DIST_EPSILON)/(t1-t2); 645 if (frac < 0) 646 frac = 0; 647 if (frac > 1) 648 frac = 1; 649 650 midf = p1f + (p2f - p1f)*frac; 651 for (i=0 ; i<3 ; i++) 652 mid[i] = p1[i] + frac*(p2[i] - p1[i]); 653 654 side = (t1 < 0); 655 656 // move up to the node 657 if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) 658 return false; 659 660 #ifdef PARANOID 661 if (SV_HullPointContents (sv_hullmodel, mid, node->children[side]) 662 == CONTENTS_SOLID) 663 { 664 Con_Printf ("mid PointInHullSolid\n"); 665 return false; 666 } 667 #endif 668 669 if (SV_HullPointContents (hull, node->children[side^1], mid) 670 != CONTENTS_SOLID) 671 // go past the node 672 return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); 673 674 if (trace->allsolid) 675 return false; // never got out of the solid area 676 677 //================== 678 // the other side of the node is solid, this is the impact point 679 //================== 680 if (!side) 681 { 682 VectorCopy (plane->normal, trace->plane.normal); 683 trace->plane.dist = plane->dist; 684 } 685 else 686 { 687 VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); 688 trace->plane.dist = -plane->dist; 689 } 690 691 while (SV_HullPointContents (hull, hull->firstclipnode, mid) 692 == CONTENTS_SOLID) 693 { // shouldn't really happen, but does occasionally 694 frac -= 0.1; 695 if (frac < 0) 696 { 697 trace->fraction = midf; 698 VectorCopy (mid, trace->endpos); 699 Con_DPrintf ("backup past 0\n"); 700 return false; 701 } 702 midf = p1f + (p2f - p1f)*frac; 703 for (i=0 ; i<3 ; i++) 704 mid[i] = p1[i] + frac*(p2[i] - p1[i]); 705 } 706 707 trace->fraction = midf; 708 VectorCopy (mid, trace->endpos); 709 710 return false; 711 } 712 713 714 /* 715 ================== 716 SV_ClipMoveToEntity 717 718 Handles selection or creation of a clipping hull, and offseting (and 719 eventually rotation) of the end points 720 ================== 721 */ 722 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) 723 { 724 trace_t trace; 725 vec3_t offset; 726 vec3_t start_l, end_l; 727 hull_t *hull; 728 729 // fill in a default trace 730 memset (&trace, 0, sizeof(trace_t)); 731 trace.fraction = 1; 732 trace.allsolid = true; 733 VectorCopy (end, trace.endpos); 734 735 // get the clipping hull 736 hull = SV_HullForEntity (ent, mins, maxs, offset); 737 738 VectorSubtract (start, offset, start_l); 739 VectorSubtract (end, offset, end_l); 740 741 #ifdef QUAKE2 742 // rotate start and end into the models frame of reference 743 if (ent->u.v.solid == SOLID_BSP && 744 (ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) ) 745 { 746 vec3_t a; 747 vec3_t forward, right, up; 748 vec3_t temp; 749 750 AngleVectors (ent->u.v.angles, forward, right, up); 751 752 VectorCopy (start_l, temp); 753 start_l[0] = DotProduct (temp, forward); 754 start_l[1] = -DotProduct (temp, right); 755 start_l[2] = DotProduct (temp, up); 756 757 VectorCopy (end_l, temp); 758 end_l[0] = DotProduct (temp, forward); 759 end_l[1] = -DotProduct (temp, right); 760 end_l[2] = DotProduct (temp, up); 761 } 762 #endif 763 764 // trace a line through the apropriate clipping hull 765 SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); 766 767 #ifdef QUAKE2 768 // rotate endpos back to world frame of reference 769 if (ent->u.v.solid == SOLID_BSP && 770 (ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) ) 771 { 772 vec3_t a; 773 vec3_t forward, right, up; 774 vec3_t temp; 775 776 if (trace.fraction != 1) 777 { 778 VectorSubtract (vec3_origin, ent->u.v.angles, a); 779 AngleVectors (a, forward, right, up); 780 781 VectorCopy (trace.endpos, temp); 782 trace.endpos[0] = DotProduct (temp, forward); 783 trace.endpos[1] = -DotProduct (temp, right); 784 trace.endpos[2] = DotProduct (temp, up); 785 786 VectorCopy (trace.plane.normal, temp); 787 trace.plane.normal[0] = DotProduct (temp, forward); 788 trace.plane.normal[1] = -DotProduct (temp, right); 789 trace.plane.normal[2] = DotProduct (temp, up); 790 } 791 } 792 #endif 793 794 // fix trace up by the offset 795 if (trace.fraction != 1) 796 VectorAdd (trace.endpos, offset, trace.endpos); 797 798 // did we clip the move? 799 if (trace.fraction < 1 || trace.startsolid ) 800 trace.ent = ent; 801 802 return trace; 803 } 804 805 //=========================================================================== 806 807 /* 808 ==================== 809 SV_ClipToLinks 810 811 Mins and maxs enclose the entire area swept by the move 812 ==================== 813 */ 814 void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip ) 815 { 816 link_t *l, *next; 817 edict_t *touch; 818 trace_t trace; 819 820 // touch linked edicts 821 for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) 822 { 823 next = l->next; 824 touch = EDICT_FROM_AREA(l); 825 if (touch->u.v.solid == SOLID_NOT) 826 continue; 827 if (touch == clip->passedict) 828 continue; 829 if (touch->u.v.solid == SOLID_TRIGGER) 830 Sys_Error ("Trigger in clipping list"); 831 832 if (clip->type == MOVE_NOMONSTERS && touch->u.v.solid != SOLID_BSP) 833 continue; 834 835 if (clip->boxmins[0] > touch->u.v.absmax[0] 836 || clip->boxmins[1] > touch->u.v.absmax[1] 837 || clip->boxmins[2] > touch->u.v.absmax[2] 838 || clip->boxmaxs[0] < touch->u.v.absmin[0] 839 || clip->boxmaxs[1] < touch->u.v.absmin[1] 840 || clip->boxmaxs[2] < touch->u.v.absmin[2] ) 841 continue; 842 843 if (clip->passedict && clip->passedict->u.v.size[0] && !touch->u.v.size[0]) 844 continue; // points never interact 845 846 // might intersect, so do an exact clip 847 if (clip->trace.allsolid) 848 return; 849 if (clip->passedict) 850 { 851 if (PROG_TO_EDICT(touch->u.v.owner) == clip->passedict) 852 continue; // don't clip against own missiles 853 if (PROG_TO_EDICT(clip->passedict->u.v.owner) == touch) 854 continue; // don't clip against owner 855 } 856 857 if ((int)touch->u.v.flags & FL_MONSTER) 858 trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end); 859 else 860 trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end); 861 if (trace.allsolid || trace.startsolid || 862 trace.fraction < clip->trace.fraction) 863 { 864 trace.ent = touch; 865 if (clip->trace.startsolid) 866 { 867 clip->trace = trace; 868 clip->trace.startsolid = true; 869 } 870 else 871 clip->trace = trace; 872 } 873 else if (trace.startsolid) 874 clip->trace.startsolid = true; 875 } 876 877 // recurse down both sides 878 if (node->axis == -1) 879 return; 880 881 if ( clip->boxmaxs[node->axis] > node->dist ) 882 SV_ClipToLinks ( node->children[0], clip ); 883 if ( clip->boxmins[node->axis] < node->dist ) 884 SV_ClipToLinks ( node->children[1], clip ); 885 } 886 887 888 /* 889 ================== 890 SV_MoveBounds 891 ================== 892 */ 893 void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) 894 { 895 #if 0 896 // debug to test against everything 897 boxmins[0] = boxmins[1] = boxmins[2] = -9999; 898 boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999; 899 #else 900 int i; 901 902 for (i=0 ; i<3 ; i++) 903 { 904 if (end[i] > start[i]) 905 { 906 boxmins[i] = start[i] + mins[i] - 1; 907 boxmaxs[i] = end[i] + maxs[i] + 1; 908 } 909 else 910 { 911 boxmins[i] = end[i] + mins[i] - 1; 912 boxmaxs[i] = start[i] + maxs[i] + 1; 913 } 914 } 915 #endif 916 } 917 918 /* 919 ================== 920 SV_Move 921 ================== 922 */ 923 trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict) 924 { 925 moveclip_t clip; 926 int i; 927 928 memset ( &clip, 0, sizeof ( moveclip_t ) ); 929 930 // clip to world 931 clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end ); 932 933 clip.start = start; 934 clip.end = end; 935 clip.mins = mins; 936 clip.maxs = maxs; 937 clip.type = type; 938 clip.passedict = passedict; 939 940 if (type == MOVE_MISSILE) 941 { 942 for (i=0 ; i<3 ; i++) 943 { 944 clip.mins2[i] = -15; 945 clip.maxs2[i] = 15; 946 } 947 } 948 else 949 { 950 VectorCopy (mins, clip.mins2); 951 VectorCopy (maxs, clip.maxs2); 952 } 953 954 // create the bounding box of the entire move 955 SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); 956 957 // clip to entities 958 SV_ClipToLinks ( sv_areanodes, &clip ); 959 960 return clip.trace; 961 } 962 963