be_aas_sample.c (44151B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 /***************************************************************************** 24 * name: be_aas_sample.c 25 * 26 * desc: AAS environment sampling 27 * 28 * $Archive: /MissionPack/code/botlib/be_aas_sample.c $ 29 * 30 *****************************************************************************/ 31 32 #include "../game/q_shared.h" 33 #include "l_memory.h" 34 #include "l_script.h" 35 #include "l_precomp.h" 36 #include "l_struct.h" 37 #ifndef BSPC 38 #include "l_libvar.h" 39 #endif 40 #include "aasfile.h" 41 #include "../game/botlib.h" 42 #include "../game/be_aas.h" 43 #include "be_interface.h" 44 #include "be_aas_funcs.h" 45 #include "be_aas_def.h" 46 47 extern botlib_import_t botimport; 48 49 //#define AAS_SAMPLE_DEBUG 50 51 #define BBOX_NORMAL_EPSILON 0.001 52 53 #define ON_EPSILON 0 //0.0005 54 55 #define TRACEPLANE_EPSILON 0.125 56 57 typedef struct aas_tracestack_s 58 { 59 vec3_t start; //start point of the piece of line to trace 60 vec3_t end; //end point of the piece of line to trace 61 int planenum; //last plane used as splitter 62 int nodenum; //node found after splitting with planenum 63 } aas_tracestack_t; 64 65 int numaaslinks; 66 67 //=========================================================================== 68 // 69 // Parameter: - 70 // Returns: - 71 // Changes Globals: - 72 //=========================================================================== 73 void AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) 74 { 75 int index; 76 //bounding box size for each presence type 77 vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}}; 78 vec3_t boxmaxs[3] = {{0, 0, 0}, { 15, 15, 32}, { 15, 15, 8}}; 79 80 if (presencetype == PRESENCE_NORMAL) index = 1; 81 else if (presencetype == PRESENCE_CROUCH) index = 2; 82 else 83 { 84 botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n"); 85 index = 2; 86 } //end if 87 VectorCopy(boxmins[index], mins); 88 VectorCopy(boxmaxs[index], maxs); 89 } //end of the function AAS_PresenceTypeBoundingBox 90 //=========================================================================== 91 // 92 // Parameter: - 93 // Returns: - 94 // Changes Globals: - 95 //=========================================================================== 96 void AAS_InitAASLinkHeap(void) 97 { 98 int i, max_aaslinks; 99 100 max_aaslinks = aasworld.linkheapsize; 101 //if there's no link heap present 102 if (!aasworld.linkheap) 103 { 104 #ifdef BSPC 105 max_aaslinks = 6144; 106 #else 107 max_aaslinks = (int) LibVarValue("max_aaslinks", "6144"); 108 #endif 109 if (max_aaslinks < 0) max_aaslinks = 0; 110 aasworld.linkheapsize = max_aaslinks; 111 aasworld.linkheap = (aas_link_t *) GetHunkMemory(max_aaslinks * sizeof(aas_link_t)); 112 } //end if 113 //link the links on the heap 114 aasworld.linkheap[0].prev_ent = NULL; 115 aasworld.linkheap[0].next_ent = &aasworld.linkheap[1]; 116 for (i = 1; i < max_aaslinks-1; i++) 117 { 118 aasworld.linkheap[i].prev_ent = &aasworld.linkheap[i - 1]; 119 aasworld.linkheap[i].next_ent = &aasworld.linkheap[i + 1]; 120 } //end for 121 aasworld.linkheap[max_aaslinks-1].prev_ent = &aasworld.linkheap[max_aaslinks-2]; 122 aasworld.linkheap[max_aaslinks-1].next_ent = NULL; 123 //pointer to the first free link 124 aasworld.freelinks = &aasworld.linkheap[0]; 125 // 126 numaaslinks = max_aaslinks; 127 } //end of the function AAS_InitAASLinkHeap 128 //=========================================================================== 129 // 130 // Parameter: - 131 // Returns: - 132 // Changes Globals: - 133 //=========================================================================== 134 void AAS_FreeAASLinkHeap(void) 135 { 136 if (aasworld.linkheap) FreeMemory(aasworld.linkheap); 137 aasworld.linkheap = NULL; 138 aasworld.linkheapsize = 0; 139 } //end of the function AAS_FreeAASLinkHeap 140 //=========================================================================== 141 // 142 // Parameter: - 143 // Returns: - 144 // Changes Globals: - 145 //=========================================================================== 146 aas_link_t *AAS_AllocAASLink(void) 147 { 148 aas_link_t *link; 149 150 link = aasworld.freelinks; 151 if (!link) 152 { 153 #ifndef BSPC 154 if (bot_developer) 155 #endif 156 { 157 botimport.Print(PRT_FATAL, "empty aas link heap\n"); 158 } //end if 159 return NULL; 160 } //end if 161 if (aasworld.freelinks) aasworld.freelinks = aasworld.freelinks->next_ent; 162 if (aasworld.freelinks) aasworld.freelinks->prev_ent = NULL; 163 numaaslinks--; 164 return link; 165 } //end of the function AAS_AllocAASLink 166 //=========================================================================== 167 // 168 // Parameter: - 169 // Returns: - 170 // Changes Globals: - 171 //=========================================================================== 172 void AAS_DeAllocAASLink(aas_link_t *link) 173 { 174 if (aasworld.freelinks) aasworld.freelinks->prev_ent = link; 175 link->prev_ent = NULL; 176 link->next_ent = aasworld.freelinks; 177 link->prev_area = NULL; 178 link->next_area = NULL; 179 aasworld.freelinks = link; 180 numaaslinks++; 181 } //end of the function AAS_DeAllocAASLink 182 //=========================================================================== 183 // 184 // Parameter: - 185 // Returns: - 186 // Changes Globals: - 187 //=========================================================================== 188 void AAS_InitAASLinkedEntities(void) 189 { 190 if (!aasworld.loaded) return; 191 if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); 192 aasworld.arealinkedentities = (aas_link_t **) GetClearedHunkMemory( 193 aasworld.numareas * sizeof(aas_link_t *)); 194 } //end of the function AAS_InitAASLinkedEntities 195 //=========================================================================== 196 // 197 // Parameter: - 198 // Returns: - 199 // Changes Globals: - 200 //=========================================================================== 201 void AAS_FreeAASLinkedEntities(void) 202 { 203 if (aasworld.arealinkedentities) FreeMemory(aasworld.arealinkedentities); 204 aasworld.arealinkedentities = NULL; 205 } //end of the function AAS_InitAASLinkedEntities 206 //=========================================================================== 207 // returns the AAS area the point is in 208 // 209 // Parameter: - 210 // Returns: - 211 // Changes Globals: - 212 //=========================================================================== 213 int AAS_PointAreaNum(vec3_t point) 214 { 215 int nodenum; 216 vec_t dist; 217 aas_node_t *node; 218 aas_plane_t *plane; 219 220 if (!aasworld.loaded) 221 { 222 botimport.Print(PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n"); 223 return 0; 224 } //end if 225 226 //start with node 1 because node zero is a dummy used for solid leafs 227 nodenum = 1; 228 while (nodenum > 0) 229 { 230 // botimport.Print(PRT_MESSAGE, "[%d]", nodenum); 231 #ifdef AAS_SAMPLE_DEBUG 232 if (nodenum >= aasworld.numnodes) 233 { 234 botimport.Print(PRT_ERROR, "nodenum = %d >= aasworld.numnodes = %d\n", nodenum, aasworld.numnodes); 235 return 0; 236 } //end if 237 #endif //AAS_SAMPLE_DEBUG 238 node = &aasworld.nodes[nodenum]; 239 #ifdef AAS_SAMPLE_DEBUG 240 if (node->planenum < 0 || node->planenum >= aasworld.numplanes) 241 { 242 botimport.Print(PRT_ERROR, "node->planenum = %d >= aasworld.numplanes = %d\n", node->planenum, aasworld.numplanes); 243 return 0; 244 } //end if 245 #endif //AAS_SAMPLE_DEBUG 246 plane = &aasworld.planes[node->planenum]; 247 dist = DotProduct(point, plane->normal) - plane->dist; 248 if (dist > 0) nodenum = node->children[0]; 249 else nodenum = node->children[1]; 250 } //end while 251 if (!nodenum) 252 { 253 #ifdef AAS_SAMPLE_DEBUG 254 botimport.Print(PRT_MESSAGE, "in solid\n"); 255 #endif //AAS_SAMPLE_DEBUG 256 return 0; 257 } //end if 258 return -nodenum; 259 } //end of the function AAS_PointAreaNum 260 //=========================================================================== 261 // 262 // Parameter: - 263 // Returns: - 264 // Changes Globals: - 265 //=========================================================================== 266 int AAS_PointReachabilityAreaIndex( vec3_t origin ) 267 { 268 int areanum, cluster, i, index; 269 270 if (!aasworld.initialized) 271 return 0; 272 273 if ( !origin ) 274 { 275 index = 0; 276 for (i = 0; i < aasworld.numclusters; i++) 277 { 278 index += aasworld.clusters[i].numreachabilityareas; 279 } //end for 280 return index; 281 } //end if 282 283 areanum = AAS_PointAreaNum( origin ); 284 if ( !areanum || !AAS_AreaReachability(areanum) ) 285 return 0; 286 cluster = aasworld.areasettings[areanum].cluster; 287 areanum = aasworld.areasettings[areanum].clusterareanum; 288 if (cluster < 0) 289 { 290 cluster = aasworld.portals[-cluster].frontcluster; 291 areanum = aasworld.portals[-cluster].clusterareanum[0]; 292 } //end if 293 294 index = 0; 295 for (i = 0; i < cluster; i++) 296 { 297 index += aasworld.clusters[i].numreachabilityareas; 298 } //end for 299 index += areanum; 300 return index; 301 } //end of the function AAS_PointReachabilityAreaIndex 302 //=========================================================================== 303 // 304 // Parameter: - 305 // Returns: - 306 // Changes Globals: - 307 //=========================================================================== 308 int AAS_AreaCluster(int areanum) 309 { 310 if (areanum <= 0 || areanum >= aasworld.numareas) 311 { 312 botimport.Print(PRT_ERROR, "AAS_AreaCluster: invalid area number\n"); 313 return 0; 314 } //end if 315 return aasworld.areasettings[areanum].cluster; 316 } //end of the function AAS_AreaCluster 317 //=========================================================================== 318 // returns the presence types of the given area 319 // 320 // Parameter: - 321 // Returns: - 322 // Changes Globals: - 323 //=========================================================================== 324 int AAS_AreaPresenceType(int areanum) 325 { 326 if (!aasworld.loaded) return 0; 327 if (areanum <= 0 || areanum >= aasworld.numareas) 328 { 329 botimport.Print(PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n"); 330 return 0; 331 } //end if 332 return aasworld.areasettings[areanum].presencetype; 333 } //end of the function AAS_AreaPresenceType 334 //=========================================================================== 335 // returns the presence type at the given point 336 // 337 // Parameter: - 338 // Returns: - 339 // Changes Globals: - 340 //=========================================================================== 341 int AAS_PointPresenceType(vec3_t point) 342 { 343 int areanum; 344 345 if (!aasworld.loaded) return 0; 346 347 areanum = AAS_PointAreaNum(point); 348 if (!areanum) return PRESENCE_NONE; 349 return aasworld.areasettings[areanum].presencetype; 350 } //end of the function AAS_PointPresenceType 351 //=========================================================================== 352 // calculates the minimum distance between the origin of the box and the 353 // given plane when both will collide on the given side of the plane 354 // 355 // normal = normal vector of plane to calculate distance from 356 // mins = minimums of box relative to origin 357 // maxs = maximums of box relative to origin 358 // side = side of the plane we want to calculate the distance from 359 // 0 normal vector side 360 // 1 not normal vector side 361 // 362 // Parameter: - 363 // Returns: - 364 // Changes Globals: - 365 //=========================================================================== 366 vec_t AAS_BoxOriginDistanceFromPlane(vec3_t normal, vec3_t mins, vec3_t maxs, int side) 367 { 368 vec3_t v1, v2; 369 int i; 370 371 //swap maxs and mins when on the other side of the plane 372 if (side) 373 { 374 //get a point of the box that would be one of the first 375 //to collide with the plane 376 for (i = 0; i < 3; i++) 377 { 378 if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; 379 else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = mins[i]; 380 else v1[i] = 0; 381 } //end for 382 } //end if 383 else 384 { 385 //get a point of the box that would be one of the first 386 //to collide with the plane 387 for (i = 0; i < 3; i++) 388 { 389 if (normal[i] > BBOX_NORMAL_EPSILON) v1[i] = mins[i]; 390 else if (normal[i] < -BBOX_NORMAL_EPSILON) v1[i] = maxs[i]; 391 else v1[i] = 0; 392 } //end for 393 } //end else 394 // 395 VectorCopy(normal, v2); 396 VectorInverse(v2); 397 // VectorNegate(normal, v2); 398 return DotProduct(v1, v2); 399 } //end of the function AAS_BoxOriginDistanceFromPlane 400 //=========================================================================== 401 // 402 // Parameter: - 403 // Returns: - 404 // Changes Globals: - 405 //=========================================================================== 406 qboolean AAS_AreaEntityCollision(int areanum, vec3_t start, vec3_t end, 407 int presencetype, int passent, aas_trace_t *trace) 408 { 409 int collision; 410 vec3_t boxmins, boxmaxs; 411 aas_link_t *link; 412 bsp_trace_t bsptrace; 413 414 AAS_PresenceTypeBoundingBox(presencetype, boxmins, boxmaxs); 415 416 Com_Memset(&bsptrace, 0, sizeof(bsp_trace_t)); //make compiler happy 417 //assume no collision 418 bsptrace.fraction = 1; 419 collision = qfalse; 420 for (link = aasworld.arealinkedentities[areanum]; link; link = link->next_ent) 421 { 422 //ignore the pass entity 423 if (link->entnum == passent) continue; 424 // 425 if (AAS_EntityCollision(link->entnum, start, boxmins, boxmaxs, end, 426 CONTENTS_SOLID|CONTENTS_PLAYERCLIP, &bsptrace)) 427 { 428 collision = qtrue; 429 } //end if 430 } //end for 431 if (collision) 432 { 433 trace->startsolid = bsptrace.startsolid; 434 trace->ent = bsptrace.ent; 435 VectorCopy(bsptrace.endpos, trace->endpos); 436 trace->area = 0; 437 trace->planenum = 0; 438 return qtrue; 439 } //end if 440 return qfalse; 441 } //end of the function AAS_AreaEntityCollision 442 //=========================================================================== 443 // recursive subdivision of the line by the BSP tree. 444 // 445 // Parameter: - 446 // Returns: - 447 // Changes Globals: - 448 //=========================================================================== 449 aas_trace_t AAS_TraceClientBBox(vec3_t start, vec3_t end, int presencetype, 450 int passent) 451 { 452 int side, nodenum, tmpplanenum; 453 float front, back, frac; 454 vec3_t cur_start, cur_end, cur_mid, v1, v2; 455 aas_tracestack_t tracestack[127]; 456 aas_tracestack_t *tstack_p; 457 aas_node_t *aasnode; 458 aas_plane_t *plane; 459 aas_trace_t trace; 460 461 //clear the trace structure 462 Com_Memset(&trace, 0, sizeof(aas_trace_t)); 463 464 if (!aasworld.loaded) return trace; 465 466 tstack_p = tracestack; 467 //we start with the whole line on the stack 468 VectorCopy(start, tstack_p->start); 469 VectorCopy(end, tstack_p->end); 470 tstack_p->planenum = 0; 471 //start with node 1 because node zero is a dummy for a solid leaf 472 tstack_p->nodenum = 1; //starting at the root of the tree 473 tstack_p++; 474 475 while (1) 476 { 477 //pop up the stack 478 tstack_p--; 479 //if the trace stack is empty (ended up with a piece of the 480 //line to be traced in an area) 481 if (tstack_p < tracestack) 482 { 483 tstack_p++; 484 //nothing was hit 485 trace.startsolid = qfalse; 486 trace.fraction = 1.0; 487 //endpos is the end of the line 488 VectorCopy(end, trace.endpos); 489 //nothing hit 490 trace.ent = 0; 491 trace.area = 0; 492 trace.planenum = 0; 493 return trace; 494 } //end if 495 //number of the current node to test the line against 496 nodenum = tstack_p->nodenum; 497 //if it is an area 498 if (nodenum < 0) 499 { 500 #ifdef AAS_SAMPLE_DEBUG 501 if (-nodenum > aasworld.numareasettings) 502 { 503 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n"); 504 return trace; 505 } //end if 506 #endif //AAS_SAMPLE_DEBUG 507 //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); 508 //if can't enter the area because it hasn't got the right presence type 509 if (!(aasworld.areasettings[-nodenum].presencetype & presencetype)) 510 { 511 //if the start point is still the initial start point 512 //NOTE: no need for epsilons because the points will be 513 //exactly the same when they're both the start point 514 if (tstack_p->start[0] == start[0] && 515 tstack_p->start[1] == start[1] && 516 tstack_p->start[2] == start[2]) 517 { 518 trace.startsolid = qtrue; 519 trace.fraction = 0.0; 520 VectorClear(v1); 521 } //end if 522 else 523 { 524 trace.startsolid = qfalse; 525 VectorSubtract(end, start, v1); 526 VectorSubtract(tstack_p->start, start, v2); 527 trace.fraction = VectorLength(v2) / VectorNormalize(v1); 528 VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); 529 } //end else 530 VectorCopy(tstack_p->start, trace.endpos); 531 trace.ent = 0; 532 trace.area = -nodenum; 533 // VectorSubtract(end, start, v1); 534 trace.planenum = tstack_p->planenum; 535 //always take the plane with normal facing towards the trace start 536 plane = &aasworld.planes[trace.planenum]; 537 if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; 538 return trace; 539 } //end if 540 else 541 { 542 if (passent >= 0) 543 { 544 if (AAS_AreaEntityCollision(-nodenum, tstack_p->start, 545 tstack_p->end, presencetype, passent, 546 &trace)) 547 { 548 if (!trace.startsolid) 549 { 550 VectorSubtract(end, start, v1); 551 VectorSubtract(trace.endpos, start, v2); 552 trace.fraction = VectorLength(v2) / VectorLength(v1); 553 } //end if 554 return trace; 555 } //end if 556 } //end if 557 } //end else 558 trace.lastarea = -nodenum; 559 continue; 560 } //end if 561 //if it is a solid leaf 562 if (!nodenum) 563 { 564 //if the start point is still the initial start point 565 //NOTE: no need for epsilons because the points will be 566 //exactly the same when they're both the start point 567 if (tstack_p->start[0] == start[0] && 568 tstack_p->start[1] == start[1] && 569 tstack_p->start[2] == start[2]) 570 { 571 trace.startsolid = qtrue; 572 trace.fraction = 0.0; 573 VectorClear(v1); 574 } //end if 575 else 576 { 577 trace.startsolid = qfalse; 578 VectorSubtract(end, start, v1); 579 VectorSubtract(tstack_p->start, start, v2); 580 trace.fraction = VectorLength(v2) / VectorNormalize(v1); 581 VectorMA(tstack_p->start, -0.125, v1, tstack_p->start); 582 } //end else 583 VectorCopy(tstack_p->start, trace.endpos); 584 trace.ent = 0; 585 trace.area = 0; //hit solid leaf 586 // VectorSubtract(end, start, v1); 587 trace.planenum = tstack_p->planenum; 588 //always take the plane with normal facing towards the trace start 589 plane = &aasworld.planes[trace.planenum]; 590 if (DotProduct(v1, plane->normal) > 0) trace.planenum ^= 1; 591 return trace; 592 } //end if 593 #ifdef AAS_SAMPLE_DEBUG 594 if (nodenum > aasworld.numnodes) 595 { 596 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n"); 597 return trace; 598 } //end if 599 #endif //AAS_SAMPLE_DEBUG 600 //the node to test against 601 aasnode = &aasworld.nodes[nodenum]; 602 //start point of current line to test against node 603 VectorCopy(tstack_p->start, cur_start); 604 //end point of the current line to test against node 605 VectorCopy(tstack_p->end, cur_end); 606 //the current node plane 607 plane = &aasworld.planes[aasnode->planenum]; 608 609 switch(plane->type) 610 {/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!! 611 //check for axial planes 612 case PLANE_X: 613 { 614 front = cur_start[0] - plane->dist; 615 back = cur_end[0] - plane->dist; 616 break; 617 } //end case 618 case PLANE_Y: 619 { 620 front = cur_start[1] - plane->dist; 621 back = cur_end[1] - plane->dist; 622 break; 623 } //end case 624 case PLANE_Z: 625 { 626 front = cur_start[2] - plane->dist; 627 back = cur_end[2] - plane->dist; 628 break; 629 } //end case*/ 630 default: //gee it's not an axial plane 631 { 632 front = DotProduct(cur_start, plane->normal) - plane->dist; 633 back = DotProduct(cur_end, plane->normal) - plane->dist; 634 break; 635 } //end default 636 } //end switch 637 // bk010221 - old location of FPE hack and divide by zero expression 638 //if the whole to be traced line is totally at the front of this node 639 //only go down the tree with the front child 640 if ((front >= -ON_EPSILON && back >= -ON_EPSILON)) 641 { 642 //keep the current start and end point on the stack 643 //and go down the tree with the front child 644 tstack_p->nodenum = aasnode->children[0]; 645 tstack_p++; 646 if (tstack_p >= &tracestack[127]) 647 { 648 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); 649 return trace; 650 } //end if 651 } //end if 652 //if the whole to be traced line is totally at the back of this node 653 //only go down the tree with the back child 654 else if ((front < ON_EPSILON && back < ON_EPSILON)) 655 { 656 //keep the current start and end point on the stack 657 //and go down the tree with the back child 658 tstack_p->nodenum = aasnode->children[1]; 659 tstack_p++; 660 if (tstack_p >= &tracestack[127]) 661 { 662 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); 663 return trace; 664 } //end if 665 } //end if 666 //go down the tree both at the front and back of the node 667 else 668 { 669 tmpplanenum = tstack_p->planenum; 670 // bk010221 - new location of divide by zero (see above) 671 if ( front == back ) front -= 0.001f; // bk0101022 - hack/FPE 672 //calculate the hitpoint with the node (split point of the line) 673 //put the crosspoint TRACEPLANE_EPSILON pixels on the near side 674 if (front < 0) frac = (front + TRACEPLANE_EPSILON)/(front-back); 675 else frac = (front - TRACEPLANE_EPSILON)/(front-back); // bk010221 676 // 677 if (frac < 0) 678 frac = 0.001f; //0 679 else if (frac > 1) 680 frac = 0.999f; //1 681 //frac = front / (front-back); 682 // 683 cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; 684 cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; 685 cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; 686 687 // AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); 688 //side the front part of the line is on 689 side = front < 0; 690 //first put the end part of the line on the stack (back side) 691 VectorCopy(cur_mid, tstack_p->start); 692 //not necesary to store because still on stack 693 //VectorCopy(cur_end, tstack_p->end); 694 tstack_p->planenum = aasnode->planenum; 695 tstack_p->nodenum = aasnode->children[!side]; 696 tstack_p++; 697 if (tstack_p >= &tracestack[127]) 698 { 699 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); 700 return trace; 701 } //end if 702 //now put the part near the start of the line on the stack so we will 703 //continue with thats part first. This way we'll find the first 704 //hit of the bbox 705 VectorCopy(cur_start, tstack_p->start); 706 VectorCopy(cur_mid, tstack_p->end); 707 tstack_p->planenum = tmpplanenum; 708 tstack_p->nodenum = aasnode->children[side]; 709 tstack_p++; 710 if (tstack_p >= &tracestack[127]) 711 { 712 botimport.Print(PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n"); 713 return trace; 714 } //end if 715 } //end else 716 } //end while 717 // return trace; 718 } //end of the function AAS_TraceClientBBox 719 //=========================================================================== 720 // recursive subdivision of the line by the BSP tree. 721 // 722 // Parameter: - 723 // Returns: - 724 // Changes Globals: - 725 //=========================================================================== 726 int AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) 727 { 728 int side, nodenum, tmpplanenum; 729 int numareas; 730 float front, back, frac; 731 vec3_t cur_start, cur_end, cur_mid; 732 aas_tracestack_t tracestack[127]; 733 aas_tracestack_t *tstack_p; 734 aas_node_t *aasnode; 735 aas_plane_t *plane; 736 737 numareas = 0; 738 areas[0] = 0; 739 if (!aasworld.loaded) return numareas; 740 741 tstack_p = tracestack; 742 //we start with the whole line on the stack 743 VectorCopy(start, tstack_p->start); 744 VectorCopy(end, tstack_p->end); 745 tstack_p->planenum = 0; 746 //start with node 1 because node zero is a dummy for a solid leaf 747 tstack_p->nodenum = 1; //starting at the root of the tree 748 tstack_p++; 749 750 while (1) 751 { 752 //pop up the stack 753 tstack_p--; 754 //if the trace stack is empty (ended up with a piece of the 755 //line to be traced in an area) 756 if (tstack_p < tracestack) 757 { 758 return numareas; 759 } //end if 760 //number of the current node to test the line against 761 nodenum = tstack_p->nodenum; 762 //if it is an area 763 if (nodenum < 0) 764 { 765 #ifdef AAS_SAMPLE_DEBUG 766 if (-nodenum > aasworld.numareasettings) 767 { 768 botimport.Print(PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum); 769 return numareas; 770 } //end if 771 #endif //AAS_SAMPLE_DEBUG 772 //botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start)); 773 areas[numareas] = -nodenum; 774 if (points) VectorCopy(tstack_p->start, points[numareas]); 775 numareas++; 776 if (numareas >= maxareas) return numareas; 777 continue; 778 } //end if 779 //if it is a solid leaf 780 if (!nodenum) 781 { 782 continue; 783 } //end if 784 #ifdef AAS_SAMPLE_DEBUG 785 if (nodenum > aasworld.numnodes) 786 { 787 botimport.Print(PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n"); 788 return numareas; 789 } //end if 790 #endif //AAS_SAMPLE_DEBUG 791 //the node to test against 792 aasnode = &aasworld.nodes[nodenum]; 793 //start point of current line to test against node 794 VectorCopy(tstack_p->start, cur_start); 795 //end point of the current line to test against node 796 VectorCopy(tstack_p->end, cur_end); 797 //the current node plane 798 plane = &aasworld.planes[aasnode->planenum]; 799 800 switch(plane->type) 801 {/*FIXME: wtf doesn't this work? obviously the node planes aren't always facing positive!!! 802 //check for axial planes 803 case PLANE_X: 804 { 805 front = cur_start[0] - plane->dist; 806 back = cur_end[0] - plane->dist; 807 break; 808 } //end case 809 case PLANE_Y: 810 { 811 front = cur_start[1] - plane->dist; 812 back = cur_end[1] - plane->dist; 813 break; 814 } //end case 815 case PLANE_Z: 816 { 817 front = cur_start[2] - plane->dist; 818 back = cur_end[2] - plane->dist; 819 break; 820 } //end case*/ 821 default: //gee it's not an axial plane 822 { 823 front = DotProduct(cur_start, plane->normal) - plane->dist; 824 back = DotProduct(cur_end, plane->normal) - plane->dist; 825 break; 826 } //end default 827 } //end switch 828 829 //if the whole to be traced line is totally at the front of this node 830 //only go down the tree with the front child 831 if (front > 0 && back > 0) 832 { 833 //keep the current start and end point on the stack 834 //and go down the tree with the front child 835 tstack_p->nodenum = aasnode->children[0]; 836 tstack_p++; 837 if (tstack_p >= &tracestack[127]) 838 { 839 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); 840 return numareas; 841 } //end if 842 } //end if 843 //if the whole to be traced line is totally at the back of this node 844 //only go down the tree with the back child 845 else if (front <= 0 && back <= 0) 846 { 847 //keep the current start and end point on the stack 848 //and go down the tree with the back child 849 tstack_p->nodenum = aasnode->children[1]; 850 tstack_p++; 851 if (tstack_p >= &tracestack[127]) 852 { 853 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); 854 return numareas; 855 } //end if 856 } //end if 857 //go down the tree both at the front and back of the node 858 else 859 { 860 tmpplanenum = tstack_p->planenum; 861 //calculate the hitpoint with the node (split point of the line) 862 //put the crosspoint TRACEPLANE_EPSILON pixels on the near side 863 if (front < 0) frac = (front)/(front-back); 864 else frac = (front)/(front-back); 865 if (frac < 0) frac = 0; 866 else if (frac > 1) frac = 1; 867 //frac = front / (front-back); 868 // 869 cur_mid[0] = cur_start[0] + (cur_end[0] - cur_start[0]) * frac; 870 cur_mid[1] = cur_start[1] + (cur_end[1] - cur_start[1]) * frac; 871 cur_mid[2] = cur_start[2] + (cur_end[2] - cur_start[2]) * frac; 872 873 // AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED); 874 //side the front part of the line is on 875 side = front < 0; 876 //first put the end part of the line on the stack (back side) 877 VectorCopy(cur_mid, tstack_p->start); 878 //not necesary to store because still on stack 879 //VectorCopy(cur_end, tstack_p->end); 880 tstack_p->planenum = aasnode->planenum; 881 tstack_p->nodenum = aasnode->children[!side]; 882 tstack_p++; 883 if (tstack_p >= &tracestack[127]) 884 { 885 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); 886 return numareas; 887 } //end if 888 //now put the part near the start of the line on the stack so we will 889 //continue with thats part first. This way we'll find the first 890 //hit of the bbox 891 VectorCopy(cur_start, tstack_p->start); 892 VectorCopy(cur_mid, tstack_p->end); 893 tstack_p->planenum = tmpplanenum; 894 tstack_p->nodenum = aasnode->children[side]; 895 tstack_p++; 896 if (tstack_p >= &tracestack[127]) 897 { 898 botimport.Print(PRT_ERROR, "AAS_TraceAreas: stack overflow\n"); 899 return numareas; 900 } //end if 901 } //end else 902 } //end while 903 // return numareas; 904 } //end of the function AAS_TraceAreas 905 //=========================================================================== 906 // a simple cross product 907 // 908 // Parameter: - 909 // Returns: - 910 // Changes Globals: - 911 //=========================================================================== 912 // void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res) 913 #define AAS_OrthogonalToVectors(v1, v2, res) \ 914 (res)[0] = ((v1)[1] * (v2)[2]) - ((v1)[2] * (v2)[1]);\ 915 (res)[1] = ((v1)[2] * (v2)[0]) - ((v1)[0] * (v2)[2]);\ 916 (res)[2] = ((v1)[0] * (v2)[1]) - ((v1)[1] * (v2)[0]); 917 //=========================================================================== 918 // tests if the given point is within the face boundaries 919 // 920 // Parameter: face : face to test if the point is in it 921 // pnormal : normal of the plane to use for the face 922 // point : point to test if inside face boundaries 923 // Returns: qtrue if the point is within the face boundaries 924 // Changes Globals: - 925 //=========================================================================== 926 qboolean AAS_InsideFace(aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon) 927 { 928 int i, firstvertex, edgenum; 929 vec3_t v0; 930 vec3_t edgevec, pointvec, sepnormal; 931 aas_edge_t *edge; 932 #ifdef AAS_SAMPLE_DEBUG 933 int lastvertex = 0; 934 #endif //AAS_SAMPLE_DEBUG 935 936 if (!aasworld.loaded) return qfalse; 937 938 for (i = 0; i < face->numedges; i++) 939 { 940 edgenum = aasworld.edgeindex[face->firstedge + i]; 941 edge = &aasworld.edges[abs(edgenum)]; 942 //get the first vertex of the edge 943 firstvertex = edgenum < 0; 944 VectorCopy(aasworld.vertexes[edge->v[firstvertex]], v0); 945 //edge vector 946 VectorSubtract(aasworld.vertexes[edge->v[!firstvertex]], v0, edgevec); 947 // 948 #ifdef AAS_SAMPLE_DEBUG 949 if (lastvertex && lastvertex != edge->v[firstvertex]) 950 { 951 botimport.Print(PRT_MESSAGE, "winding not counter clockwise\n"); 952 } //end if 953 lastvertex = edge->v[!firstvertex]; 954 #endif //AAS_SAMPLE_DEBUG 955 //vector from first edge point to point possible in face 956 VectorSubtract(point, v0, pointvec); 957 //get a vector pointing inside the face orthogonal to both the 958 //edge vector and the normal vector of the plane the face is in 959 //this vector defines a plane through the origin (first vertex of 960 //edge) and through both the edge vector and the normal vector 961 //of the plane 962 AAS_OrthogonalToVectors(edgevec, pnormal, sepnormal); 963 //check on wich side of the above plane the point is 964 //this is done by checking the sign of the dot product of the 965 //vector orthogonal vector from above and the vector from the 966 //origin (first vertex of edge) to the point 967 //if the dotproduct is smaller than zero the point is outside the face 968 if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; 969 } //end for 970 return qtrue; 971 } //end of the function AAS_InsideFace 972 //=========================================================================== 973 // 974 // Parameter: - 975 // Returns: - 976 // Changes Globals: - 977 //=========================================================================== 978 qboolean AAS_PointInsideFace(int facenum, vec3_t point, float epsilon) 979 { 980 int i, firstvertex, edgenum; 981 vec_t *v1, *v2; 982 vec3_t edgevec, pointvec, sepnormal; 983 aas_edge_t *edge; 984 aas_plane_t *plane; 985 aas_face_t *face; 986 987 if (!aasworld.loaded) return qfalse; 988 989 face = &aasworld.faces[facenum]; 990 plane = &aasworld.planes[face->planenum]; 991 // 992 for (i = 0; i < face->numedges; i++) 993 { 994 edgenum = aasworld.edgeindex[face->firstedge + i]; 995 edge = &aasworld.edges[abs(edgenum)]; 996 //get the first vertex of the edge 997 firstvertex = edgenum < 0; 998 v1 = aasworld.vertexes[edge->v[firstvertex]]; 999 v2 = aasworld.vertexes[edge->v[!firstvertex]]; 1000 //edge vector 1001 VectorSubtract(v2, v1, edgevec); 1002 //vector from first edge point to point possible in face 1003 VectorSubtract(point, v1, pointvec); 1004 // 1005 CrossProduct(edgevec, plane->normal, sepnormal); 1006 // 1007 if (DotProduct(pointvec, sepnormal) < -epsilon) return qfalse; 1008 } //end for 1009 return qtrue; 1010 } //end of the function AAS_PointInsideFace 1011 //=========================================================================== 1012 // returns the ground face the given point is above in the given area 1013 // 1014 // Parameter: - 1015 // Returns: - 1016 // Changes Globals: - 1017 //=========================================================================== 1018 aas_face_t *AAS_AreaGroundFace(int areanum, vec3_t point) 1019 { 1020 int i, facenum; 1021 vec3_t up = {0, 0, 1}; 1022 vec3_t normal; 1023 aas_area_t *area; 1024 aas_face_t *face; 1025 1026 if (!aasworld.loaded) return NULL; 1027 1028 area = &aasworld.areas[areanum]; 1029 for (i = 0; i < area->numfaces; i++) 1030 { 1031 facenum = aasworld.faceindex[area->firstface + i]; 1032 face = &aasworld.faces[abs(facenum)]; 1033 //if this is a ground face 1034 if (face->faceflags & FACE_GROUND) 1035 { 1036 //get the up or down normal 1037 if (aasworld.planes[face->planenum].normal[2] < 0) VectorNegate(up, normal); 1038 else VectorCopy(up, normal); 1039 //check if the point is in the face 1040 if (AAS_InsideFace(face, normal, point, 0.01f)) return face; 1041 } //end if 1042 } //end for 1043 return NULL; 1044 } //end of the function AAS_AreaGroundFace 1045 //=========================================================================== 1046 // returns the face the trace end position is situated in 1047 // 1048 // Parameter: - 1049 // Returns: - 1050 // Changes Globals: - 1051 //=========================================================================== 1052 void AAS_FacePlane(int facenum, vec3_t normal, float *dist) 1053 { 1054 aas_plane_t *plane; 1055 1056 plane = &aasworld.planes[aasworld.faces[facenum].planenum]; 1057 VectorCopy(plane->normal, normal); 1058 *dist = plane->dist; 1059 } //end of the function AAS_FacePlane 1060 //=========================================================================== 1061 // returns the face the trace end position is situated in 1062 // 1063 // Parameter: - 1064 // Returns: - 1065 // Changes Globals: - 1066 //=========================================================================== 1067 aas_face_t *AAS_TraceEndFace(aas_trace_t *trace) 1068 { 1069 int i, facenum; 1070 aas_area_t *area; 1071 aas_face_t *face, *firstface = NULL; 1072 1073 if (!aasworld.loaded) return NULL; 1074 1075 //if started in solid no face was hit 1076 if (trace->startsolid) return NULL; 1077 //trace->lastarea is the last area the trace was in 1078 area = &aasworld.areas[trace->lastarea]; 1079 //check which face the trace.endpos was in 1080 for (i = 0; i < area->numfaces; i++) 1081 { 1082 facenum = aasworld.faceindex[area->firstface + i]; 1083 face = &aasworld.faces[abs(facenum)]; 1084 //if the face is in the same plane as the trace end point 1085 if ((face->planenum & ~1) == (trace->planenum & ~1)) 1086 { 1087 //firstface is used for optimization, if theres only one 1088 //face in the plane then it has to be the good one 1089 //if there are more faces in the same plane then always 1090 //check the one with the fewest edges first 1091 /* if (firstface) 1092 { 1093 if (firstface->numedges < face->numedges) 1094 { 1095 if (AAS_InsideFace(firstface, 1096 aasworld.planes[face->planenum].normal, trace->endpos)) 1097 { 1098 return firstface; 1099 } //end if 1100 firstface = face; 1101 } //end if 1102 else 1103 { 1104 if (AAS_InsideFace(face, 1105 aasworld.planes[face->planenum].normal, trace->endpos)) 1106 { 1107 return face; 1108 } //end if 1109 } //end else 1110 } //end if 1111 else 1112 { 1113 firstface = face; 1114 } //end else*/ 1115 if (AAS_InsideFace(face, 1116 aasworld.planes[face->planenum].normal, trace->endpos, 0.01f)) return face; 1117 } //end if 1118 } //end for 1119 return firstface; 1120 } //end of the function AAS_TraceEndFace 1121 //=========================================================================== 1122 // 1123 // Parameter: - 1124 // Returns: - 1125 // Changes Globals: - 1126 //=========================================================================== 1127 int AAS_BoxOnPlaneSide2(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) 1128 { 1129 int i, sides; 1130 float dist1, dist2; 1131 vec3_t corners[2]; 1132 1133 for (i = 0; i < 3; i++) 1134 { 1135 if (p->normal[i] < 0) 1136 { 1137 corners[0][i] = absmins[i]; 1138 corners[1][i] = absmaxs[i]; 1139 } //end if 1140 else 1141 { 1142 corners[1][i] = absmins[i]; 1143 corners[0][i] = absmaxs[i]; 1144 } //end else 1145 } //end for 1146 dist1 = DotProduct(p->normal, corners[0]) - p->dist; 1147 dist2 = DotProduct(p->normal, corners[1]) - p->dist; 1148 sides = 0; 1149 if (dist1 >= 0) sides = 1; 1150 if (dist2 < 0) sides |= 2; 1151 1152 return sides; 1153 } //end of the function AAS_BoxOnPlaneSide2 1154 //=========================================================================== 1155 // 1156 // Parameter: - 1157 // Returns: - 1158 // Changes Globals: - 1159 //=========================================================================== 1160 //int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p) 1161 #define AAS_BoxOnPlaneSide(absmins, absmaxs, p) (\ 1162 ( (p)->type < 3) ?\ 1163 (\ 1164 ( (p)->dist <= (absmins)[(p)->type]) ?\ 1165 (\ 1166 1\ 1167 )\ 1168 :\ 1169 (\ 1170 ( (p)->dist >= (absmaxs)[(p)->type]) ?\ 1171 (\ 1172 2\ 1173 )\ 1174 :\ 1175 (\ 1176 3\ 1177 )\ 1178 )\ 1179 )\ 1180 :\ 1181 (\ 1182 AAS_BoxOnPlaneSide2((absmins), (absmaxs), (p))\ 1183 )\ 1184 ) //end of the function AAS_BoxOnPlaneSide 1185 //=========================================================================== 1186 // remove the links to this entity from all areas 1187 // 1188 // Parameter: - 1189 // Returns: - 1190 // Changes Globals: - 1191 //=========================================================================== 1192 void AAS_UnlinkFromAreas(aas_link_t *areas) 1193 { 1194 aas_link_t *link, *nextlink; 1195 1196 for (link = areas; link; link = nextlink) 1197 { 1198 //next area the entity is linked in 1199 nextlink = link->next_area; 1200 //remove the entity from the linked list of this area 1201 if (link->prev_ent) link->prev_ent->next_ent = link->next_ent; 1202 else aasworld.arealinkedentities[link->areanum] = link->next_ent; 1203 if (link->next_ent) link->next_ent->prev_ent = link->prev_ent; 1204 //deallocate the link structure 1205 AAS_DeAllocAASLink(link); 1206 } //end for 1207 } //end of the function AAS_UnlinkFromAreas 1208 //=========================================================================== 1209 // link the entity to the areas the bounding box is totally or partly 1210 // situated in. This is done with recursion down the tree using the 1211 // bounding box to test for plane sides 1212 // 1213 // Parameter: - 1214 // Returns: - 1215 // Changes Globals: - 1216 //=========================================================================== 1217 1218 typedef struct 1219 { 1220 int nodenum; //node found after splitting 1221 } aas_linkstack_t; 1222 1223 aas_link_t *AAS_AASLinkEntity(vec3_t absmins, vec3_t absmaxs, int entnum) 1224 { 1225 int side, nodenum; 1226 aas_linkstack_t linkstack[128]; 1227 aas_linkstack_t *lstack_p; 1228 aas_node_t *aasnode; 1229 aas_plane_t *plane; 1230 aas_link_t *link, *areas; 1231 1232 if (!aasworld.loaded) 1233 { 1234 botimport.Print(PRT_ERROR, "AAS_LinkEntity: aas not loaded\n"); 1235 return NULL; 1236 } //end if 1237 1238 areas = NULL; 1239 // 1240 lstack_p = linkstack; 1241 //we start with the whole line on the stack 1242 //start with node 1 because node zero is a dummy used for solid leafs 1243 lstack_p->nodenum = 1; //starting at the root of the tree 1244 lstack_p++; 1245 1246 while (1) 1247 { 1248 //pop up the stack 1249 lstack_p--; 1250 //if the trace stack is empty (ended up with a piece of the 1251 //line to be traced in an area) 1252 if (lstack_p < linkstack) break; 1253 //number of the current node to test the line against 1254 nodenum = lstack_p->nodenum; 1255 //if it is an area 1256 if (nodenum < 0) 1257 { 1258 //NOTE: the entity might have already been linked into this area 1259 // because several node children can point to the same area 1260 for (link = aasworld.arealinkedentities[-nodenum]; link; link = link->next_ent) 1261 { 1262 if (link->entnum == entnum) break; 1263 } //end for 1264 if (link) continue; 1265 // 1266 link = AAS_AllocAASLink(); 1267 if (!link) return areas; 1268 link->entnum = entnum; 1269 link->areanum = -nodenum; 1270 //put the link into the double linked area list of the entity 1271 link->prev_area = NULL; 1272 link->next_area = areas; 1273 if (areas) areas->prev_area = link; 1274 areas = link; 1275 //put the link into the double linked entity list of the area 1276 link->prev_ent = NULL; 1277 link->next_ent = aasworld.arealinkedentities[-nodenum]; 1278 if (aasworld.arealinkedentities[-nodenum]) 1279 aasworld.arealinkedentities[-nodenum]->prev_ent = link; 1280 aasworld.arealinkedentities[-nodenum] = link; 1281 // 1282 continue; 1283 } //end if 1284 //if solid leaf 1285 if (!nodenum) continue; 1286 //the node to test against 1287 aasnode = &aasworld.nodes[nodenum]; 1288 //the current node plane 1289 plane = &aasworld.planes[aasnode->planenum]; 1290 //get the side(s) the box is situated relative to the plane 1291 side = AAS_BoxOnPlaneSide2(absmins, absmaxs, plane); 1292 //if on the front side of the node 1293 if (side & 1) 1294 { 1295 lstack_p->nodenum = aasnode->children[0]; 1296 lstack_p++; 1297 } //end if 1298 if (lstack_p >= &linkstack[127]) 1299 { 1300 botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); 1301 break; 1302 } //end if 1303 //if on the back side of the node 1304 if (side & 2) 1305 { 1306 lstack_p->nodenum = aasnode->children[1]; 1307 lstack_p++; 1308 } //end if 1309 if (lstack_p >= &linkstack[127]) 1310 { 1311 botimport.Print(PRT_ERROR, "AAS_LinkEntity: stack overflow\n"); 1312 break; 1313 } //end if 1314 } //end while 1315 return areas; 1316 } //end of the function AAS_AASLinkEntity 1317 //=========================================================================== 1318 // 1319 // Parameter: - 1320 // Returns: - 1321 // Changes Globals: - 1322 //=========================================================================== 1323 aas_link_t *AAS_LinkEntityClientBBox(vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype) 1324 { 1325 vec3_t mins, maxs; 1326 vec3_t newabsmins, newabsmaxs; 1327 1328 AAS_PresenceTypeBoundingBox(presencetype, mins, maxs); 1329 VectorSubtract(absmins, maxs, newabsmins); 1330 VectorSubtract(absmaxs, mins, newabsmaxs); 1331 //relink the entity 1332 return AAS_AASLinkEntity(newabsmins, newabsmaxs, entnum); 1333 } //end of the function AAS_LinkEntityClientBBox 1334 //=========================================================================== 1335 // 1336 // Parameter: - 1337 // Returns: - 1338 // Changes Globals: - 1339 //=========================================================================== 1340 int AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) 1341 { 1342 aas_link_t *linkedareas, *link; 1343 int num; 1344 1345 linkedareas = AAS_AASLinkEntity(absmins, absmaxs, -1); 1346 num = 0; 1347 for (link = linkedareas; link; link = link->next_area) 1348 { 1349 areas[num] = link->areanum; 1350 num++; 1351 if (num >= maxareas) 1352 break; 1353 } //end for 1354 AAS_UnlinkFromAreas(linkedareas); 1355 return num; 1356 } //end of the function AAS_BBoxAreas 1357 //=========================================================================== 1358 // 1359 // Parameter: - 1360 // Returns: - 1361 // Changes Globals: - 1362 //=========================================================================== 1363 int AAS_AreaInfo( int areanum, aas_areainfo_t *info ) 1364 { 1365 aas_areasettings_t *settings; 1366 if (!info) 1367 return 0; 1368 if (areanum <= 0 || areanum >= aasworld.numareas) 1369 { 1370 botimport.Print(PRT_ERROR, "AAS_AreaInfo: areanum %d out of range\n", areanum); 1371 return 0; 1372 } //end if 1373 settings = &aasworld.areasettings[areanum]; 1374 info->cluster = settings->cluster; 1375 info->contents = settings->contents; 1376 info->flags = settings->areaflags; 1377 info->presencetype = settings->presencetype; 1378 VectorCopy(aasworld.areas[areanum].mins, info->mins); 1379 VectorCopy(aasworld.areas[areanum].maxs, info->maxs); 1380 VectorCopy(aasworld.areas[areanum].center, info->center); 1381 return sizeof(aas_areainfo_t); 1382 } //end of the function AAS_AreaInfo 1383 //=========================================================================== 1384 // 1385 // Parameter: - 1386 // Returns: - 1387 // Changes Globals: - 1388 //=========================================================================== 1389 aas_plane_t *AAS_PlaneFromNum(int planenum) 1390 { 1391 if (!aasworld.loaded) return 0; 1392 1393 return &aasworld.planes[planenum]; 1394 } //end of the function AAS_PlaneFromNum