00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "../game/q_shared.h"
00033 #include "l_log.h"
00034 #include "l_memory.h"
00035 #include "l_script.h"
00036 #include "l_libvar.h"
00037 #include "l_precomp.h"
00038 #include "l_struct.h"
00039 #include "aasfile.h"
00040 #include "../game/botlib.h"
00041 #include "../game/be_aas.h"
00042 #include "be_aas_funcs.h"
00043 #include "be_aas_def.h"
00044
00045 extern int Sys_MilliSeconds(void);
00046
00047
00048 extern botlib_import_t botimport;
00049
00050
00051
00052
00053
00054 #define AAS_MAX_REACHABILITYSIZE 65536
00055
00056 #define REACHABILITYAREASPERCYCLE 15
00057
00058 #define INSIDEUNITS 2
00059 #define INSIDEUNITS_WALKEND 5
00060 #define INSIDEUNITS_WALKSTART 0.1
00061 #define INSIDEUNITS_WATERJUMP 15
00062
00063 #define AREA_WEAPONJUMP 8192 //valid area to weapon jump to
00064
00065 int reach_swim;
00066 int reach_equalfloor;
00067 int reach_step;
00068 int reach_walk;
00069 int reach_barrier;
00070 int reach_waterjump;
00071 int reach_walkoffledge;
00072 int reach_jump;
00073 int reach_ladder;
00074 int reach_teleport;
00075 int reach_elevator;
00076 int reach_funcbob;
00077 int reach_grapple;
00078 int reach_doublejump;
00079 int reach_rampjump;
00080 int reach_strafejump;
00081 int reach_rocketjump;
00082 int reach_bfgjump;
00083 int reach_jumppad;
00084
00085 int calcgrapplereach;
00086
00087 typedef struct aas_lreachability_s
00088 {
00089 int areanum;
00090 int facenum;
00091 int edgenum;
00092 vec3_t start;
00093 vec3_t end;
00094 int traveltype;
00095 unsigned short int traveltime;
00096
00097 struct aas_lreachability_s *next;
00098 } aas_lreachability_t;
00099
00100 aas_lreachability_t *reachabilityheap;
00101 aas_lreachability_t *nextreachability;
00102 aas_lreachability_t **areareachability;
00103 int numlreachabilities;
00104
00105
00106
00107
00108
00109
00110
00111
00112 float AAS_FaceArea(aas_face_t *face)
00113 {
00114 int i, edgenum, side;
00115 float total;
00116 vec_t *v;
00117 vec3_t d1, d2, cross;
00118 aas_edge_t *edge;
00119
00120 edgenum = aasworld.edgeindex[face->firstedge];
00121 side = edgenum < 0;
00122 edge = &aasworld.edges[abs(edgenum)];
00123 v = aasworld.vertexes[edge->v[side]];
00124
00125 total = 0;
00126 for (i = 1; i < face->numedges - 1; i++)
00127 {
00128 edgenum = aasworld.edgeindex[face->firstedge + i];
00129 side = edgenum < 0;
00130 edge = &aasworld.edges[abs(edgenum)];
00131 VectorSubtract(aasworld.vertexes[edge->v[side]], v, d1);
00132 VectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2);
00133 CrossProduct(d1, d2, cross);
00134 total += 0.5 * VectorLength(cross);
00135 }
00136 return total;
00137 }
00138
00139
00140
00141
00142
00143
00144
00145 float AAS_AreaVolume(int areanum)
00146 {
00147 int i, edgenum, facenum, side;
00148 vec_t d, a, volume;
00149 vec3_t corner;
00150 aas_plane_t *plane;
00151 aas_edge_t *edge;
00152 aas_face_t *face;
00153 aas_area_t *area;
00154
00155 area = &aasworld.areas[areanum];
00156 facenum = aasworld.faceindex[area->firstface];
00157 face = &aasworld.faces[abs(facenum)];
00158 edgenum = aasworld.edgeindex[face->firstedge];
00159 edge = &aasworld.edges[abs(edgenum)];
00160
00161 VectorCopy(aasworld.vertexes[edge->v[0]], corner);
00162
00163
00164 volume = 0;
00165 for (i = 0; i < area->numfaces; i++)
00166 {
00167 facenum = abs(aasworld.faceindex[area->firstface + i]);
00168 face = &aasworld.faces[facenum];
00169 side = face->backarea != areanum;
00170 plane = &aasworld.planes[face->planenum ^ side];
00171 d = -(DotProduct (corner, plane->normal) - plane->dist);
00172 a = AAS_FaceArea(face);
00173 volume += d * a;
00174 }
00175
00176 volume /= 3;
00177 return volume;
00178 }
00179
00180
00181
00182
00183
00184
00185 int AAS_BestReachableLinkArea(aas_link_t *areas)
00186 {
00187 aas_link_t *link;
00188
00189 for (link = areas; link; link = link->next_area)
00190 {
00191 if (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum))
00192 {
00193 return link->areanum;
00194 }
00195 }
00196
00197 for (link = areas; link; link = link->next_area)
00198 {
00199 if (link->areanum) return link->areanum;
00200
00201
00202 if (AAS_AreaReachability(link->areanum))
00203 return link->areanum;
00204 }
00205 return 0;
00206 }
00207
00208
00209
00210
00211
00212
00213 int AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity)
00214 {
00215 int modelnum, ent2;
00216 float speed, height, gravity, time, dist, forward;
00217 vec3_t origin, angles, teststart, ent2origin;
00218 aas_trace_t trace;
00219 char model[MAX_EPAIRKEY];
00220 char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY];
00221
00222
00223 AAS_FloatForBSPEpairKey(ent, "speed", &speed);
00224 if (!speed) speed = 1000;
00225 VectorClear(angles);
00226
00227 AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY);
00228 if (model[0]) modelnum = atoi(model+1);
00229 else modelnum = 0;
00230 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin);
00231 VectorAdd(origin, absmins, absmins);
00232 VectorAdd(origin, absmaxs, absmaxs);
00233 VectorAdd(absmins, absmaxs, origin);
00234 VectorScale (origin, 0.5, origin);
00235
00236
00237 VectorCopy(origin, teststart);
00238 teststart[2] += 64;
00239 trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1);
00240 if (trace.startsolid)
00241 {
00242 botimport.Print(PRT_MESSAGE, "trigger_push start solid\n");
00243 VectorCopy(origin, areastart);
00244 }
00245 else
00246 {
00247 VectorCopy(trace.endpos, areastart);
00248 }
00249 areastart[2] += 0.125;
00250
00251
00252
00253 AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY);
00254 for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2))
00255 {
00256 if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue;
00257 if (!strcmp(targetname, target)) break;
00258 }
00259 if (!ent2)
00260 {
00261 botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target);
00262 return qfalse;
00263 }
00264 AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin);
00265
00266 height = ent2origin[2] - origin[2];
00267 gravity = aassettings.phys_gravity;
00268 time = sqrt( height / ( 0.5 * gravity ) );
00269 if (!time)
00270 {
00271 botimport.Print(PRT_MESSAGE, "trigger_push without time\n");
00272 return qfalse;
00273 }
00274
00275 VectorSubtract ( ent2origin, origin, velocity);
00276 dist = VectorNormalize( velocity);
00277 forward = dist / time;
00278
00279 forward *= 1.1f;
00280 VectorScale(velocity, forward, velocity);
00281 velocity[2] = time * gravity;
00282 return qtrue;
00283 }
00284
00285
00286
00287
00288
00289
00290 int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs)
00291 {
00292 int area2num, ent, bot_visualizejumppads, bestareanum;
00293 float volume, bestareavolume;
00294 vec3_t areastart, cmdmove, bboxmins, bboxmaxs;
00295 vec3_t absmins, absmaxs, velocity;
00296 aas_clientmove_t move;
00297 aas_link_t *areas, *link;
00298 char classname[MAX_EPAIRKEY];
00299
00300 #ifdef BSPC
00301 bot_visualizejumppads = 0;
00302 #else
00303 bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0");
00304 #endif
00305 VectorAdd(origin, mins, bboxmins);
00306 VectorAdd(origin, maxs, bboxmaxs);
00307 for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
00308 {
00309 if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
00310 if (strcmp(classname, "trigger_push")) continue;
00311
00312 if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue;
00313
00314 areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);
00315 for (link = areas; link; link = link->next_area)
00316 {
00317 if (AAS_AreaJumpPad(link->areanum)) break;
00318 }
00319 if (!link)
00320 {
00321 botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n");
00322 AAS_UnlinkFromAreas(areas);
00323 continue;
00324 }
00325
00326
00327
00328 VectorSet(cmdmove, 0, 0, 0);
00329 Com_Memset(&move, 0, sizeof(aas_clientmove_t));
00330 area2num = 0;
00331 AAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse,
00332 velocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads);
00333 if (move.frames < 30)
00334 {
00335 bestareanum = 0;
00336 bestareavolume = 0;
00337 for (link = areas; link; link = link->next_area)
00338 {
00339 if (!AAS_AreaJumpPad(link->areanum)) continue;
00340 volume = AAS_AreaVolume(link->areanum);
00341 if (volume >= bestareavolume)
00342 {
00343 bestareanum = link->areanum;
00344 bestareavolume = volume;
00345 }
00346 }
00347 AAS_UnlinkFromAreas(areas);
00348 return bestareanum;
00349 }
00350 AAS_UnlinkFromAreas(areas);
00351 }
00352 return 0;
00353 }
00354
00355
00356
00357
00358
00359
00360 int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin)
00361 {
00362 int areanum, i, j, k, l;
00363 aas_link_t *areas;
00364 vec3_t absmins, absmaxs;
00365
00366 vec3_t start, end;
00367 aas_trace_t trace;
00368
00369 if (!aasworld.loaded)
00370 {
00371 botimport.Print(PRT_ERROR, "AAS_BestReachableArea: aas not loaded\n");
00372 return 0;
00373 }
00374
00375 VectorCopy(origin, start);
00376 areanum = AAS_PointAreaNum(start);
00377
00378 for (i = 0; i < 5 && !areanum; i++)
00379 {
00380 for (j = 0; j < 5 && !areanum; j++)
00381 {
00382 for (k = -1; k <= 1 && !areanum; k++)
00383 {
00384 for (l = -1; l <= 1 && !areanum; l++)
00385 {
00386 VectorCopy(origin, start);
00387 start[0] += (float) j * 4 * k;
00388 start[1] += (float) j * 4 * l;
00389 start[2] += (float) i * 4;
00390 areanum = AAS_PointAreaNum(start);
00391 }
00392 }
00393 }
00394 }
00395
00396 if (areanum)
00397 {
00398
00399 VectorCopy(start, end);
00400 start[2] += 0.25;
00401 end[2] -= 50;
00402 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
00403 if (!trace.startsolid)
00404 {
00405 areanum = AAS_PointAreaNum(trace.endpos);
00406 VectorCopy(trace.endpos, goalorigin);
00407
00408
00409
00410
00411 if (areanum) return areanum;
00412 }
00413 else
00414 {
00415
00416
00417
00418 #if 0
00419 if (AAS_PointAreaNum(start))
00420 {
00421 Log_Write("point %f %f %f in area %d but trace startsolid", start[0], start[1], start[2], areanum);
00422 AAS_DrawPermanentCross(start, 4, LINECOLOR_RED);
00423 }
00424 botimport.Print(PRT_MESSAGE, "AAS_BestReachableArea: start solid\n");
00425 #endif
00426 VectorCopy(start, goalorigin);
00427 return areanum;
00428 }
00429 }
00430
00431
00432
00433
00434 VectorCopy(origin, goalorigin);
00435
00436 VectorAdd(origin, mins, absmins);
00437 VectorAdd(origin, maxs, absmaxs);
00438
00439
00440
00441
00442 areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH);
00443
00444 areanum = AAS_BestReachableLinkArea(areas);
00445
00446 AAS_UnlinkFromAreas(areas);
00447
00448 return areanum;
00449 }
00450
00451
00452
00453
00454
00455
00456 void AAS_SetupReachabilityHeap(void)
00457 {
00458 int i;
00459
00460 reachabilityheap = (aas_lreachability_t *) GetClearedMemory(
00461 AAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t));
00462 for (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++)
00463 {
00464 reachabilityheap[i].next = &reachabilityheap[i+1];
00465 }
00466 reachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL;
00467 nextreachability = reachabilityheap;
00468 numlreachabilities = 0;
00469 }
00470
00471
00472
00473
00474
00475
00476 void AAS_ShutDownReachabilityHeap(void)
00477 {
00478 FreeMemory(reachabilityheap);
00479 numlreachabilities = 0;
00480 }
00481
00482
00483
00484
00485
00486
00487
00488 aas_lreachability_t *AAS_AllocReachability(void)
00489 {
00490 aas_lreachability_t *r;
00491
00492 if (!nextreachability) return NULL;
00493
00494 if (!nextreachability->next) AAS_Error("AAS_MAX_REACHABILITYSIZE");
00495
00496 r = nextreachability;
00497 nextreachability = nextreachability->next;
00498 numlreachabilities++;
00499 return r;
00500 }
00501
00502
00503
00504
00505
00506
00507
00508 void AAS_FreeReachability(aas_lreachability_t *lreach)
00509 {
00510 Com_Memset(lreach, 0, sizeof(aas_lreachability_t));
00511
00512 lreach->next = nextreachability;
00513 nextreachability = lreach;
00514 numlreachabilities--;
00515 }
00516
00517
00518
00519
00520
00521
00522
00523 int AAS_AreaReachability(int areanum)
00524 {
00525 if (areanum < 0 || areanum >= aasworld.numareas)
00526 {
00527 AAS_Error("AAS_AreaReachability: areanum %d out of range", areanum);
00528 return 0;
00529 }
00530 return aasworld.areasettings[areanum].numreachableareas;
00531 }
00532
00533
00534
00535
00536
00537
00538
00539 float AAS_AreaGroundFaceArea(int areanum)
00540 {
00541 int i;
00542 float total;
00543 aas_area_t *area;
00544 aas_face_t *face;
00545
00546 total = 0;
00547 area = &aasworld.areas[areanum];
00548 for (i = 0; i < area->numfaces; i++)
00549 {
00550 face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])];
00551 if (!(face->faceflags & FACE_GROUND)) continue;
00552
00553 total += AAS_FaceArea(face);
00554 }
00555 return total;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564 void AAS_FaceCenter(int facenum, vec3_t center)
00565 {
00566 int i;
00567 float scale;
00568 aas_face_t *face;
00569 aas_edge_t *edge;
00570
00571 face = &aasworld.faces[facenum];
00572
00573 VectorClear(center);
00574 for (i = 0; i < face->numedges; i++)
00575 {
00576 edge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])];
00577 VectorAdd(center, aasworld.vertexes[edge->v[0]], center);
00578 VectorAdd(center, aasworld.vertexes[edge->v[1]], center);
00579 }
00580 scale = 0.5 / face->numedges;
00581 VectorScale(center, scale, center);
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591 int AAS_FallDamageDistance(void)
00592 {
00593 float maxzvelocity, gravity, t;
00594
00595 maxzvelocity = sqrt(30 * 10000);
00596 gravity = aassettings.phys_gravity;
00597 t = maxzvelocity / gravity;
00598 return 0.5 * gravity * t * t;
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609 float AAS_FallDelta(float distance)
00610 {
00611 float t, delta, gravity;
00612
00613 gravity = aassettings.phys_gravity;
00614 t = sqrt(fabs(distance) * 2 / gravity);
00615 delta = t * gravity;
00616 return delta * delta * 0.0001;
00617 }
00618
00619
00620
00621
00622
00623
00624 float AAS_MaxJumpHeight(float phys_jumpvel)
00625 {
00626 float phys_gravity;
00627
00628 phys_gravity = aassettings.phys_gravity;
00629
00630 return 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity);
00631 }
00632
00633
00634
00635
00636
00637
00638
00639 float AAS_MaxJumpDistance(float phys_jumpvel)
00640 {
00641 float phys_gravity, phys_maxvelocity, t;
00642
00643 phys_gravity = aassettings.phys_gravity;
00644 phys_maxvelocity = aassettings.phys_maxvelocity;
00645
00646 t = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity));
00647
00648 return phys_maxvelocity * (t + phys_jumpvel / phys_gravity);
00649 }
00650
00651
00652
00653
00654
00655
00656
00657 int AAS_AreaCrouch(int areanum)
00658 {
00659 if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue;
00660 else return qfalse;
00661 }
00662
00663
00664
00665
00666
00667
00668
00669 int AAS_AreaSwim(int areanum)
00670 {
00671 if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;
00672 else return qfalse;
00673 }
00674
00675
00676
00677
00678
00679
00680
00681 int AAS_AreaLiquid(int areanum)
00682 {
00683 if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue;
00684 else return qfalse;
00685 }
00686
00687
00688
00689
00690
00691
00692 int AAS_AreaLava(int areanum)
00693 {
00694 return (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA);
00695 }
00696
00697
00698
00699
00700
00701
00702 int AAS_AreaSlime(int areanum)
00703 {
00704 return (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME);
00705 }
00706
00707
00708
00709
00710
00711
00712
00713 int AAS_AreaGrounded(int areanum)
00714 {
00715 return (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED);
00716 }
00717
00718
00719
00720
00721
00722
00723
00724 int AAS_AreaLadder(int areanum)
00725 {
00726 return (aasworld.areasettings[areanum].areaflags & AREA_LADDER);
00727 }
00728
00729
00730
00731
00732
00733
00734 int AAS_AreaJumpPad(int areanum)
00735 {
00736 return (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD);
00737 }
00738
00739
00740
00741
00742
00743
00744 int AAS_AreaTeleporter(int areanum)
00745 {
00746 return (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER);
00747 }
00748
00749
00750
00751
00752
00753
00754 int AAS_AreaClusterPortal(int areanum)
00755 {
00756 return (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL);
00757 }
00758
00759
00760
00761
00762
00763
00764 int AAS_AreaDoNotEnter(int areanum)
00765 {
00766 return (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER);
00767 }
00768
00769
00770
00771
00772
00773
00774
00775 unsigned short int AAS_BarrierJumpTravelTime(void)
00776 {
00777 return aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1);
00778 }
00779
00780
00781
00782
00783
00784
00785
00786 qboolean AAS_ReachabilityExists(int area1num, int area2num)
00787 {
00788 aas_lreachability_t *r;
00789
00790 for (r = areareachability[area1num]; r; r = r->next)
00791 {
00792 if (r->areanum == area2num) return qtrue;
00793 }
00794 return qfalse;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804 int AAS_NearbySolidOrGap(vec3_t start, vec3_t end)
00805 {
00806 vec3_t dir, testpoint;
00807 int areanum;
00808
00809 VectorSubtract(end, start, dir);
00810 dir[2] = 0;
00811 VectorNormalize(dir);
00812 VectorMA(end, 48, dir, testpoint);
00813
00814 areanum = AAS_PointAreaNum(testpoint);
00815 if (!areanum)
00816 {
00817 testpoint[2] += 16;
00818 areanum = AAS_PointAreaNum(testpoint);
00819 if (!areanum) return qtrue;
00820 }
00821 VectorMA(end, 64, dir, testpoint);
00822 areanum = AAS_PointAreaNum(testpoint);
00823 if (areanum)
00824 {
00825 if (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue;
00826 }
00827 return qfalse;
00828 }
00829
00830
00831
00832
00833
00834
00835
00836 int AAS_Reachability_Swim(int area1num, int area2num)
00837 {
00838 int i, j, face1num, face2num, side1;
00839 aas_area_t *area1, *area2;
00840 aas_areasettings_t *areasettings;
00841 aas_lreachability_t *lreach;
00842 aas_face_t *face1;
00843 aas_plane_t *plane;
00844 vec3_t start;
00845
00846 if (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse;
00847
00848 if (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse;
00849
00850 area1 = &aasworld.areas[area1num];
00851 area2 = &aasworld.areas[area2num];
00852
00853
00854 for (i = 0; i < 3; i++)
00855 {
00856 if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
00857 if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
00858 }
00859
00860 for (i = 0; i < area1->numfaces; i++)
00861 {
00862 face1num = aasworld.faceindex[area1->firstface + i];
00863 side1 = face1num < 0;
00864 face1num = abs(face1num);
00865
00866 for (j = 0; j < area2->numfaces; j++)
00867 {
00868 face2num = abs(aasworld.faceindex[area2->firstface + j]);
00869
00870 if (face1num == face2num)
00871 {
00872 AAS_FaceCenter(face1num, start);
00873
00874 if (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))
00875 {
00876
00877 face1 = &aasworld.faces[face1num];
00878 areasettings = &aasworld.areasettings[area1num];
00879
00880 lreach = AAS_AllocReachability();
00881 if (!lreach) return qfalse;
00882 lreach->areanum = area2num;
00883 lreach->facenum = face1num;
00884 lreach->edgenum = 0;
00885 VectorCopy(start, lreach->start);
00886 plane = &aasworld.planes[face1->planenum ^ side1];
00887 VectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end);
00888 lreach->traveltype = TRAVEL_SWIM;
00889 lreach->traveltime = 1;
00890
00891 if (AAS_AreaVolume(area2num) < 800)
00892 lreach->traveltime += 200;
00893
00894
00895 lreach->next = areareachability[area1num];
00896 areareachability[area1num] = lreach;
00897 reach_swim++;
00898 return qtrue;
00899 }
00900 }
00901 }
00902 }
00903 return qfalse;
00904 }
00905
00906
00907
00908
00909
00910
00911
00912
00913 int AAS_Reachability_EqualFloorHeight(int area1num, int area2num)
00914 {
00915 int i, j, edgenum, edgenum1, edgenum2, foundreach, side;
00916 float height, bestheight, length, bestlength;
00917 vec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1};
00918 vec3_t edgevec;
00919 aas_area_t *area1, *area2;
00920 aas_face_t *face1, *face2;
00921 aas_edge_t *edge;
00922 aas_plane_t *plane2;
00923 aas_lreachability_t lr, *lreach;
00924
00925 if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse;
00926
00927 area1 = &aasworld.areas[area1num];
00928 area2 = &aasworld.areas[area2num];
00929
00930 for (i = 0; i < 2; i++)
00931 {
00932 if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
00933 if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
00934 }
00935
00936 if (area2->mins[2] > area1->maxs[2]) return qfalse;
00937
00938 VectorCopy(gravitydirection, invgravity);
00939 VectorInverse(invgravity);
00940
00941 bestheight = 99999;
00942 bestlength = 0;
00943 foundreach = qfalse;
00944 Com_Memset(&lr, 0, sizeof(aas_lreachability_t));
00945
00946
00947
00948 for (i = 0; i < area1->numfaces; i++)
00949 {
00950 face1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])];
00951 if (!(face1->faceflags & FACE_GROUND)) continue;
00952
00953 for (j = 0; j < area2->numfaces; j++)
00954 {
00955 face2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];
00956 if (!(face2->faceflags & FACE_GROUND)) continue;
00957
00958 for (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++)
00959 {
00960 for (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++)
00961 {
00962 if (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) !=
00963 abs(aasworld.edgeindex[face2->firstedge + edgenum2]))
00964 continue;
00965 edgenum = aasworld.edgeindex[face1->firstedge + edgenum1];
00966 side = edgenum < 0;
00967 edge = &aasworld.edges[abs(edgenum)];
00968
00969 VectorSubtract(aasworld.vertexes[edge->v[1]],
00970 aasworld.vertexes[edge->v[0]], dir);
00971 length = VectorLength(dir);
00972
00973 VectorAdd(aasworld.vertexes[edge->v[0]],
00974 aasworld.vertexes[edge->v[1]], start);
00975 VectorScale(start, 0.5, start);
00976 VectorCopy(start, end);
00977
00978
00979
00980
00981 VectorSubtract(aasworld.vertexes[edge->v[side]],
00982 aasworld.vertexes[edge->v[!side]], edgevec);
00983 plane2 = &aasworld.planes[face2->planenum];
00984 CrossProduct(edgevec, plane2->normal, normal);
00985 VectorNormalize(normal);
00986
00987
00988 VectorMA(end, INSIDEUNITS_WALKEND, normal, end);
00989 VectorMA(start, INSIDEUNITS_WALKSTART, normal, start);
00990 end[2] += 0.125;
00991
00992 height = DotProduct(invgravity, start);
00993
00994
00995
00996
00997
00998
00999 if (height < bestheight ||
01000 (height < bestheight + 1 && length > bestlength))
01001 {
01002 bestheight = height;
01003 bestlength = length;
01004
01005 lr.areanum = area2num;
01006 lr.facenum = 0;
01007 lr.edgenum = edgenum;
01008 VectorCopy(start, lr.start);
01009 VectorCopy(end, lr.end);
01010 lr.traveltype = TRAVEL_WALK;
01011 lr.traveltime = 1;
01012 foundreach = qtrue;
01013 }
01014 }
01015 }
01016 }
01017 }
01018 if (foundreach)
01019 {
01020
01021 lreach = AAS_AllocReachability();
01022 if (!lreach) return qfalse;
01023 lreach->areanum = lr.areanum;
01024 lreach->facenum = lr.facenum;
01025 lreach->edgenum = lr.edgenum;
01026 VectorCopy(lr.start, lreach->start);
01027 VectorCopy(lr.end, lreach->end);
01028 lreach->traveltype = lr.traveltype;
01029 lreach->traveltime = lr.traveltime;
01030 lreach->next = areareachability[area1num];
01031 areareachability[area1num] = lreach;
01032
01033 if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num))
01034 {
01035 lreach->traveltime += aassettings.rs_startcrouch;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 reach_equalfloor++;
01048 return qtrue;
01049 }
01050 return qfalse;
01051 }
01052
01053
01054
01055
01056
01057
01058
01059 int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num)
01060 {
01061 int i, j, k, l, edge1num, edge2num, areas[10], numareas;
01062 int ground_bestarea2groundedgenum, ground_foundreach;
01063 int water_bestarea2groundedgenum, water_foundreach;
01064 int side1, area1swim, faceside1, groundface1num;
01065 float dist, dist1, dist2, diff, invgravitydot, ortdot;
01066 float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y;
01067 float length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist;
01068 vec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2;
01069 vec3_t normal, ort, edgevec, start, end, dir;
01070 vec3_t ground_beststart, ground_bestend, ground_bestnormal;
01071 vec3_t water_beststart, water_bestend, water_bestnormal;
01072 vec3_t invgravity = {0, 0, 1};
01073 vec3_t testpoint;
01074 aas_plane_t *plane;
01075 aas_area_t *area1, *area2;
01076 aas_face_t *groundface1, *groundface2, *ground_bestface1, *water_bestface1;
01077 aas_edge_t *edge1, *edge2;
01078 aas_lreachability_t *lreach;
01079 aas_trace_t trace;
01080
01081
01082 if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse;
01083
01084 if (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse;
01085
01086 area1 = &aasworld.areas[area1num];
01087 area2 = &aasworld.areas[area2num];
01088
01089 area1swim = AAS_AreaSwim(area1num);
01090
01091 for (i = 0; i < 2; i++)
01092 {
01093 if (area1->mins[i] > area2->maxs[i] + 10) return qfalse;
01094 if (area1->maxs[i] < area2->mins[i] - 10) return qfalse;
01095 }
01096
01097 ground_foundreach = qfalse;
01098 ground_bestdist = 99999;
01099 ground_bestlength = 0;
01100 ground_bestarea2groundedgenum = 0;
01101
01102 water_foundreach = qfalse;
01103 water_bestdist = 99999;
01104 water_bestlength = 0;
01105 water_bestarea2groundedgenum = 0;
01106
01107 for (i = 0; i < area1->numfaces; i++)
01108 {
01109 groundface1num = aasworld.faceindex[area1->firstface + i];
01110 faceside1 = groundface1num < 0;
01111 groundface1 = &aasworld.faces[abs(groundface1num)];
01112
01113 if (!(groundface1->faceflags & FACE_GROUND))
01114 {
01115
01116 if (area1swim)
01117 {
01118
01119 plane = &aasworld.planes[groundface1->planenum ^ (!faceside1)];
01120 if (DotProduct(plane->normal, invgravity) < 0.7) continue;
01121 }
01122 else
01123 {
01124
01125 continue;
01126 }
01127 }
01128
01129 for (k = 0; k < groundface1->numedges; k++)
01130 {
01131 edge1num = aasworld.edgeindex[groundface1->firstedge + k];
01132 side1 = (edge1num < 0);
01133
01134
01135
01136 if (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1);
01137 edge1num = abs(edge1num);
01138 edge1 = &aasworld.edges[edge1num];
01139
01140 VectorCopy(aasworld.vertexes[edge1->v[!side1]], v1);
01141 VectorCopy(aasworld.vertexes[edge1->v[side1]], v2);
01142
01143
01144
01145 VectorSubtract(v2, v1, edgevec);
01146 CrossProduct(edgevec, invgravity, normal);
01147 VectorNormalize(normal);
01148 dist = DotProduct(normal, v1);
01149
01150 for (j = 0; j < area2->numfaces; j++)
01151 {
01152 groundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])];
01153
01154 if (!(groundface2->faceflags & FACE_GROUND)) continue;
01155
01156 for (l = 0; l < groundface2->numedges; l++)
01157 {
01158 edge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]);
01159 edge2 = &aasworld.edges[edge2num];
01160
01161 VectorCopy(aasworld.vertexes[edge2->v[0]], v3);
01162 VectorCopy(aasworld.vertexes[edge2->v[1]], v4);
01163
01164
01165 diff = DotProduct(normal, v3) - dist;
01166 if (diff < -0.1 || diff > 0.1) continue;
01167 diff = DotProduct(normal, v4) - dist;
01168 if (diff < -0.1 || diff > 0.1) continue;
01169
01170
01171
01172
01173
01174 CrossProduct(invgravity, normal, ort);
01175 invgravitydot = DotProduct(invgravity, invgravity);
01176 ortdot = DotProduct(ort, ort);
01177
01178
01179 y1 = v1[2];
01180 y2 = v2[2];
01181 y3 = v3[2];
01182 y4 = v4[2];
01183
01184 x1 = DotProduct(v1, ort)