diff options
Diffstat (limited to 'ioq3-r437/src/botlib/be_aas_reach.c')
-rw-r--r-- | ioq3-r437/src/botlib/be_aas_reach.c | 4538 |
1 files changed, 0 insertions, 4538 deletions
diff --git a/ioq3-r437/src/botlib/be_aas_reach.c b/ioq3-r437/src/botlib/be_aas_reach.c deleted file mode 100644 index 95ead20c..00000000 --- a/ioq3-r437/src/botlib/be_aas_reach.c +++ /dev/null @@ -1,4538 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code is distributed in the hope that it will be -useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -/***************************************************************************** - * name: be_aas_reach.c - * - * desc: reachability calculations - * - * $Archive: /MissionPack/code/botlib/be_aas_reach.c $ - * - *****************************************************************************/ - -#include "../qcommon/q_shared.h" -#include "l_log.h" -#include "l_memory.h" -#include "l_script.h" -#include "l_libvar.h" -#include "l_precomp.h" -#include "l_struct.h" -#include "aasfile.h" -#include "botlib.h" -#include "be_aas.h" -#include "be_aas_funcs.h" -#include "be_aas_def.h" - -extern int Sys_MilliSeconds(void); - - -extern botlib_import_t botimport; - -//#define REACH_DEBUG - -//NOTE: all travel times are in hundreth of a second -//maximum number of reachability links -#define AAS_MAX_REACHABILITYSIZE 65536 -//number of areas reachability is calculated for each frame -#define REACHABILITYAREASPERCYCLE 15 -//number of units reachability points are placed inside the areas -#define INSIDEUNITS 2 -#define INSIDEUNITS_WALKEND 5 -#define INSIDEUNITS_WALKSTART 0.1 -#define INSIDEUNITS_WATERJUMP 15 -//area flag used for weapon jumping -#define AREA_WEAPONJUMP 8192 //valid area to weapon jump to -//number of reachabilities of each type -int reach_swim; //swim -int reach_equalfloor; //walk on floors with equal height -int reach_step; //step up -int reach_walk; //walk of step -int reach_barrier; //jump up to a barrier -int reach_waterjump; //jump out of water -int reach_walkoffledge; //walk of a ledge -int reach_jump; //jump -int reach_ladder; //climb or descent a ladder -int reach_teleport; //teleport -int reach_elevator; //use an elevator -int reach_funcbob; //use a func bob -int reach_grapple; //grapple hook -int reach_doublejump; //double jump -int reach_rampjump; //ramp jump -int reach_strafejump; //strafe jump (just normal jump but further) -int reach_rocketjump; //rocket jump -int reach_bfgjump; //bfg jump -int reach_jumppad; //jump pads -//if true grapple reachabilities are skipped -int calcgrapplereach; -//linked reachability -typedef struct aas_lreachability_s -{ - int areanum; //number of the reachable area - int facenum; //number of the face towards the other area - int edgenum; //number of the edge towards the other area - vec3_t start; //start point of inter area movement - vec3_t end; //end point of inter area movement - int traveltype; //type of travel required to get to the area - unsigned short int traveltime; //travel time of the inter area movement - // - struct aas_lreachability_s *next; -} aas_lreachability_t; -//temporary reachabilities -aas_lreachability_t *reachabilityheap; //heap with reachabilities -aas_lreachability_t *nextreachability; //next free reachability from the heap -aas_lreachability_t **areareachability; //reachability links for every area -int numlreachabilities; - -//=========================================================================== -// returns the surface area of the given face -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_FaceArea(aas_face_t *face) -{ - int i, edgenum, side; - float total; - vec_t *v; - vec3_t d1, d2, cross; - aas_edge_t *edge; - - edgenum = aasworld.edgeindex[face->firstedge]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - v = aasworld.vertexes[edge->v[side]]; - - total = 0; - for (i = 1; i < face->numedges - 1; i++) - { - edgenum = aasworld.edgeindex[face->firstedge + i]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - VectorSubtract(aasworld.vertexes[edge->v[side]], v, d1); - VectorSubtract(aasworld.vertexes[edge->v[!side]], v, d2); - CrossProduct(d1, d2, cross); - total += 0.5 * VectorLength(cross); - } //end for - return total; -} //end of the function AAS_FaceArea -//=========================================================================== -// returns the volume of an area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_AreaVolume(int areanum) -{ - int i, edgenum, facenum, side; - vec_t d, a, volume; - vec3_t corner; - aas_plane_t *plane; - aas_edge_t *edge; - aas_face_t *face; - aas_area_t *area; - - area = &aasworld.areas[areanum]; - facenum = aasworld.faceindex[area->firstface]; - face = &aasworld.faces[abs(facenum)]; - edgenum = aasworld.edgeindex[face->firstedge]; - edge = &aasworld.edges[abs(edgenum)]; - // - VectorCopy(aasworld.vertexes[edge->v[0]], corner); - - //make tetrahedrons to all other faces - volume = 0; - for (i = 0; i < area->numfaces; i++) - { - facenum = abs(aasworld.faceindex[area->firstface + i]); - face = &aasworld.faces[facenum]; - side = face->backarea != areanum; - plane = &aasworld.planes[face->planenum ^ side]; - d = -(DotProduct (corner, plane->normal) - plane->dist); - a = AAS_FaceArea(face); - volume += d * a; - } //end for - - volume /= 3; - return volume; -} //end of the function AAS_AreaVolume -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableLinkArea(aas_link_t *areas) -{ - aas_link_t *link; - - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaGrounded(link->areanum) || AAS_AreaSwim(link->areanum)) - { - return link->areanum; - } //end if - } //end for - // - for (link = areas; link; link = link->next_area) - { - if (link->areanum) return link->areanum; - //FIXME: this is a bad idea when the reachability is not yet - // calculated when the level items are loaded - if (AAS_AreaReachability(link->areanum)) - return link->areanum; - } //end for - return 0; -} //end of the function AAS_BestReachableLinkArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_GetJumpPadInfo(int ent, vec3_t areastart, vec3_t absmins, vec3_t absmaxs, vec3_t velocity) -{ - int modelnum, ent2; - float speed, height, gravity, time, dist, forward; - vec3_t origin, angles, teststart, ent2origin; - aas_trace_t trace; - char model[MAX_EPAIRKEY]; - char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; - - // - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 1000; - VectorClear(angles); - //get the mins, maxs and origin of the model - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); - if (model[0]) modelnum = atoi(model+1); - else modelnum = 0; - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); - VectorAdd(origin, absmins, absmins); - VectorAdd(origin, absmaxs, absmaxs); - VectorAdd(absmins, absmaxs, origin); - VectorScale (origin, 0.5, origin); - - //get the start areas - VectorCopy(origin, teststart); - teststart[2] += 64; - trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); - VectorCopy(origin, areastart); - } //end if - else - { - VectorCopy(trace.endpos, areastart); - } //end else - areastart[2] += 0.125; - // - //AAS_DrawPermanentCross(origin, 4, 4); - //get the target entity - AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); - for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) - { - if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) break; - } //end for - if (!ent2) - { - botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); - return qfalse; - } //end if - AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); - // - height = ent2origin[2] - origin[2]; - gravity = aassettings.phys_gravity; - time = sqrt( height / ( 0.5 * gravity ) ); - if (!time) - { - botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); - return qfalse; - } //end if - // set s.origin2 to the push velocity - VectorSubtract ( ent2origin, origin, velocity); - dist = VectorNormalize( velocity); - forward = dist / time; - //FIXME: why multiply by 1.1 - forward *= 1.1f; - VectorScale(velocity, forward, velocity); - velocity[2] = time * gravity; - return qtrue; -} //end of the function AAS_GetJumpPadInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableFromJumpPadArea(vec3_t origin, vec3_t mins, vec3_t maxs) -{ - int area2num, ent, bot_visualizejumppads, bestareanum; - float volume, bestareavolume; - vec3_t areastart, cmdmove, bboxmins, bboxmaxs; - vec3_t absmins, absmaxs, velocity; - aas_clientmove_t move; - aas_link_t *areas, *link; - char classname[MAX_EPAIRKEY]; - -#ifdef BSPC - bot_visualizejumppads = 0; -#else - bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); -#endif - VectorAdd(origin, mins, bboxmins); - VectorAdd(origin, maxs, bboxmaxs); - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "trigger_push")) continue; - // - if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; - //get the areas the jump pad brush is in - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaJumpPad(link->areanum)) break; - } //end for - if (!link) - { - botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); - AAS_UnlinkFromAreas(areas); - continue; - } //end if - // - //botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); - // - VectorSet(cmdmove, 0, 0, 0); - Com_Memset(&move, 0, sizeof(aas_clientmove_t)); - area2num = 0; - AAS_ClientMovementHitBBox(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, bboxmins, bboxmaxs, bot_visualizejumppads); - if (move.frames < 30) - { - bestareanum = 0; - bestareavolume = 0; - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - volume = AAS_AreaVolume(link->areanum); - if (volume >= bestareavolume) - { - bestareanum = link->areanum; - bestareavolume = volume; - } //end if - } //end if - AAS_UnlinkFromAreas(areas); - return bestareanum; - } //end if - AAS_UnlinkFromAreas(areas); - } //end for - return 0; -} //end of the function AAS_BestReachableFromJumpPadArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_BestReachableArea(vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t goalorigin) -{ - int areanum, i, j, k, l; - aas_link_t *areas; - vec3_t absmins, absmaxs; - //vec3_t bbmins, bbmaxs; - vec3_t start, end; - aas_trace_t trace; - - if (!aasworld.loaded) - { - botimport.Print(PRT_ERROR, "AAS_BestReachableArea: aas not loaded\n"); - return 0; - } //end if - //find a point in an area - VectorCopy(origin, start); - areanum = AAS_PointAreaNum(start); - //while no area found fudge around a little - for (i = 0; i < 5 && !areanum; i++) - { - for (j = 0; j < 5 && !areanum; j++) - { - for (k = -1; k <= 1 && !areanum; k++) - { - for (l = -1; l <= 1 && !areanum; l++) - { - VectorCopy(origin, start); - start[0] += (float) j * 4 * k; - start[1] += (float) j * 4 * l; - start[2] += (float) i * 4; - areanum = AAS_PointAreaNum(start); - } //end for - } //end for - } //end for - } //end for - //if an area was found - if (areanum) - { - //drop client bbox down and try again - VectorCopy(start, end); - start[2] += 0.25; - end[2] -= 50; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (!trace.startsolid) - { - areanum = AAS_PointAreaNum(trace.endpos); - VectorCopy(trace.endpos, goalorigin); - //FIXME: cannot enable next line right now because the reachability - // does not have to be calculated when the level items are loaded - //if the origin is in an area with reachability - //if (AAS_AreaReachability(areanum)) return areanum; - if (areanum) return areanum; - } //end if - else - { - //it can very well happen that the AAS_PointAreaNum function tells that - //a point is in an area and that starting a AAS_TraceClientBBox from that - //point will return trace.startsolid qtrue -#if 0 - if (AAS_PointAreaNum(start)) - { - Log_Write("point %f %f %f in area %d but trace startsolid", start[0], start[1], start[2], areanum); - AAS_DrawPermanentCross(start, 4, LINECOLOR_RED); - } //end if - botimport.Print(PRT_MESSAGE, "AAS_BestReachableArea: start solid\n"); -#endif - VectorCopy(start, goalorigin); - return areanum; - } //end else - } //end if - // - //AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); - //NOTE: the goal origin does not have to be in the goal area - // because the bot will have to move towards the item origin anyway - VectorCopy(origin, goalorigin); - // - VectorAdd(origin, mins, absmins); - VectorAdd(origin, maxs, absmaxs); - //add bounding box size - //VectorSubtract(absmins, bbmaxs, absmins); - //VectorSubtract(absmaxs, bbmins, absmaxs); - //link an invalid (-1) entity - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - //get the reachable link arae - areanum = AAS_BestReachableLinkArea(areas); - //unlink the invalid entity - AAS_UnlinkFromAreas(areas); - // - return areanum; -} //end of the function AAS_BestReachableArea -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetupReachabilityHeap(void) -{ - int i; - - reachabilityheap = (aas_lreachability_t *) GetClearedMemory( - AAS_MAX_REACHABILITYSIZE * sizeof(aas_lreachability_t)); - for (i = 0; i < AAS_MAX_REACHABILITYSIZE-1; i++) - { - reachabilityheap[i].next = &reachabilityheap[i+1]; - } //end for - reachabilityheap[AAS_MAX_REACHABILITYSIZE-1].next = NULL; - nextreachability = reachabilityheap; - numlreachabilities = 0; -} //end of the function AAS_InitReachabilityHeap -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_ShutDownReachabilityHeap(void) -{ - FreeMemory(reachabilityheap); - numlreachabilities = 0; -} //end of the function AAS_ShutDownReachabilityHeap -//=========================================================================== -// returns a reachability link -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_lreachability_t *AAS_AllocReachability(void) -{ - aas_lreachability_t *r; - - if (!nextreachability) return NULL; - //make sure the error message only shows up once - if (!nextreachability->next) AAS_Error("AAS_MAX_REACHABILITYSIZE"); - // - r = nextreachability; - nextreachability = nextreachability->next; - numlreachabilities++; - return r; -} //end of the function AAS_AllocReachability -//=========================================================================== -// frees a reachability link -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FreeReachability(aas_lreachability_t *lreach) -{ - Com_Memset(lreach, 0, sizeof(aas_lreachability_t)); - - lreach->next = nextreachability; - nextreachability = lreach; - numlreachabilities--; -} //end of the function AAS_FreeReachability -//=========================================================================== -// returns qtrue if the area has reachability links -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaReachability(int areanum) -{ - if (areanum < 0 || areanum >= aasworld.numareas) - { - AAS_Error("AAS_AreaReachability: areanum %d out of range", areanum); - return 0; - } //end if - return aasworld.areasettings[areanum].numreachableareas; -} //end of the function AAS_AreaReachability -//=========================================================================== -// returns the surface area of all ground faces together of the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_AreaGroundFaceArea(int areanum) -{ - int i; - float total; - aas_area_t *area; - aas_face_t *face; - - total = 0; - area = &aasworld.areas[areanum]; - for (i = 0; i < area->numfaces; i++) - { - face = &aasworld.faces[abs(aasworld.faceindex[area->firstface + i])]; - if (!(face->faceflags & FACE_GROUND)) continue; - // - total += AAS_FaceArea(face); - } //end for - return total; -} //end of the function AAS_AreaGroundFaceArea -//=========================================================================== -// returns the center of a face -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_FaceCenter(int facenum, vec3_t center) -{ - int i; - float scale; - aas_face_t *face; - aas_edge_t *edge; - - face = &aasworld.faces[facenum]; - - VectorClear(center); - for (i = 0; i < face->numedges; i++) - { - edge = &aasworld.edges[abs(aasworld.edgeindex[face->firstedge + i])]; - VectorAdd(center, aasworld.vertexes[edge->v[0]], center); - VectorAdd(center, aasworld.vertexes[edge->v[1]], center); - } //end for - scale = 0.5 / face->numedges; - VectorScale(center, scale, center); -} //end of the function AAS_FaceCenter -//=========================================================================== -// returns the maximum distance a player can fall before being damaged -// damage = deltavelocity*deltavelocity * 0.0001 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_FallDamageDistance(void) -{ - float maxzvelocity, gravity, t; - - maxzvelocity = sqrt(30 * 10000); - gravity = aassettings.phys_gravity; - t = maxzvelocity / gravity; - return 0.5 * gravity * t * t; -} //end of the function AAS_FallDamageDistance -//=========================================================================== -// distance = 0.5 * gravity * t * t -// vel = t * gravity -// damage = vel * vel * 0.0001 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_FallDelta(float distance) -{ - float t, delta, gravity; - - gravity = aassettings.phys_gravity; - t = sqrt(fabs(distance) * 2 / gravity); - delta = t * gravity; - return delta * delta * 0.0001; -} //end of the function AAS_FallDelta -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_MaxJumpHeight(float phys_jumpvel) -{ - float phys_gravity; - - phys_gravity = aassettings.phys_gravity; - //maximum height a player can jump with the given initial z velocity - return 0.5 * phys_gravity * (phys_jumpvel / phys_gravity) * (phys_jumpvel / phys_gravity); -} //end of the function MaxJumpHeight -//=========================================================================== -// returns true if a player can only crouch in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float AAS_MaxJumpDistance(float phys_jumpvel) -{ - float phys_gravity, phys_maxvelocity, t; - - phys_gravity = aassettings.phys_gravity; - phys_maxvelocity = aassettings.phys_maxvelocity; - //time a player takes to fall the height - t = sqrt(aassettings.rs_maxjumpfallheight / (0.5 * phys_gravity)); - //maximum distance - return phys_maxvelocity * (t + phys_jumpvel / phys_gravity); -} //end of the function AAS_MaxJumpDistance -//=========================================================================== -// returns true if a player can only crouch in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaCrouch(int areanum) -{ - if (!(aasworld.areasettings[areanum].presencetype & PRESENCE_NORMAL)) return qtrue; - else return qfalse; -} //end of the function AAS_AreaCrouch -//=========================================================================== -// returns qtrue if it is possible to swim in the area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaSwim(int areanum) -{ - if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; - else return qfalse; -} //end of the function AAS_AreaSwim -//=========================================================================== -// returns qtrue if the area contains a liquid -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLiquid(int areanum) -{ - if (aasworld.areasettings[areanum].areaflags & AREA_LIQUID) return qtrue; - else return qfalse; -} //end of the function AAS_AreaLiquid -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLava(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_LAVA); -} //end of the function AAS_AreaLava -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaSlime(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_SLIME); -} //end of the function AAS_AreaSlime -//=========================================================================== -// returns qtrue if the area contains ground faces -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaGrounded(int areanum) -{ - return (aasworld.areasettings[areanum].areaflags & AREA_GROUNDED); -} //end of the function AAS_AreaGround -//=========================================================================== -// returns true if the area contains ladder faces -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaLadder(int areanum) -{ - return (aasworld.areasettings[areanum].areaflags & AREA_LADDER); -} //end of the function AAS_AreaLadder -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaJumpPad(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_JUMPPAD); -} //end of the function AAS_AreaJumpPad -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaTeleporter(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_TELEPORTER); -} //end of the function AAS_AreaTeleporter -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaClusterPortal(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_CLUSTERPORTAL); -} //end of the function AAS_AreaClusterPortal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_AreaDoNotEnter(int areanum) -{ - return (aasworld.areasettings[areanum].contents & AREACONTENTS_DONOTENTER); -} //end of the function AAS_AreaDoNotEnter -//=========================================================================== -// returns the time it takes perform a barrier jump -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -unsigned short int AAS_BarrierJumpTravelTime(void) -{ - return aassettings.phys_jumpvel / (aassettings.phys_gravity * 0.1); -} //end op the function AAS_BarrierJumpTravelTime -//=========================================================================== -// returns true if there already exists a reachability from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean AAS_ReachabilityExists(int area1num, int area2num) -{ - aas_lreachability_t *r; - - for (r = areareachability[area1num]; r; r = r->next) - { - if (r->areanum == area2num) return qtrue; - } //end for - return qfalse; -} //end of the function AAS_ReachabilityExists -//=========================================================================== -// returns true if there is a solid just after the end point when going -// from start to end -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_NearbySolidOrGap(vec3_t start, vec3_t end) -{ - vec3_t dir, testpoint; - int areanum; - - VectorSubtract(end, start, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorMA(end, 48, dir, testpoint); - - areanum = AAS_PointAreaNum(testpoint); - if (!areanum) - { - testpoint[2] += 16; - areanum = AAS_PointAreaNum(testpoint); - if (!areanum) return qtrue; - } //end if - VectorMA(end, 64, dir, testpoint); - areanum = AAS_PointAreaNum(testpoint); - if (areanum) - { - if (!AAS_AreaSwim(areanum) && !AAS_AreaGrounded(areanum)) return qtrue; - } //end if - return qfalse; -} //end of the function AAS_SolidGapTime -//=========================================================================== -// searches for swim reachabilities between adjacent areas -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Swim(int area1num, int area2num) -{ - int i, j, face1num, face2num, side1; - aas_area_t *area1, *area2; - aas_areasettings_t *areasettings; - aas_lreachability_t *lreach; - aas_face_t *face1; - aas_plane_t *plane; - vec3_t start; - - if (!AAS_AreaSwim(area1num) || !AAS_AreaSwim(area2num)) return qfalse; - //if the second area is crouch only - if (!(aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) return qfalse; - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - - //if the areas are not near anough - for (i = 0; i < 3; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - //find a shared face and create a reachability link - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - side1 = face1num < 0; - face1num = abs(face1num); - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = abs(aasworld.faceindex[area2->firstface + j]); - // - if (face1num == face2num) - { - AAS_FaceCenter(face1num, start); - // - if (AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER)) - { - // - face1 = &aasworld.faces[face1num]; - areasettings = &aasworld.areasettings[area1num]; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = face1num; - lreach->edgenum = 0; - VectorCopy(start, lreach->start); - plane = &aasworld.planes[face1->planenum ^ side1]; - VectorMA(lreach->start, -INSIDEUNITS, plane->normal, lreach->end); - lreach->traveltype = TRAVEL_SWIM; - lreach->traveltime = 1; - //if the volume of the area is rather small - if (AAS_AreaVolume(area2num) < 800) - lreach->traveltime += 200; - //if (!(AAS_PointContents(start) & MASK_WATER)) lreach->traveltime += 500; - //link the reachability - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - reach_swim++; - return qtrue; - } //end if - } //end if - } //end for - } //end for - return qfalse; -} //end of the function AAS_Reachability_Swim -//=========================================================================== -// searches for reachabilities between adjacent areas with equal floor -// heights -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_EqualFloorHeight(int area1num, int area2num) -{ - int i, j, edgenum, edgenum1, edgenum2, foundreach, side; - float height, bestheight, length, bestlength; - vec3_t dir, start, end, normal, invgravity, gravitydirection = {0, 0, -1}; - vec3_t edgevec; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2; - aas_edge_t *edge; - aas_plane_t *plane2; - aas_lreachability_t lr, *lreach; - - if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - //if area 2 is too high above area 1 - if (area2->mins[2] > area1->maxs[2]) return qfalse; - // - VectorCopy(gravitydirection, invgravity); - VectorInverse(invgravity); - // - bestheight = 99999; - bestlength = 0; - foundreach = qfalse; - Com_Memset(&lr, 0, sizeof(aas_lreachability_t)); //make the compiler happy - // - //check if the areas have ground faces with a common edge - //if existing use the lowest common edge for a reachability link - for (i = 0; i < area1->numfaces; i++) - { - face1 = &aasworld.faces[abs(aasworld.faceindex[area1->firstface + i])]; - if (!(face1->faceflags & FACE_GROUND)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; - if (!(face2->faceflags & FACE_GROUND)) continue; - //if there is a common edge - for (edgenum1 = 0; edgenum1 < face1->numedges; edgenum1++) - { - for (edgenum2 = 0; edgenum2 < face2->numedges; edgenum2++) - { - if (abs(aasworld.edgeindex[face1->firstedge + edgenum1]) != - abs(aasworld.edgeindex[face2->firstedge + edgenum2])) - continue; - edgenum = aasworld.edgeindex[face1->firstedge + edgenum1]; - side = edgenum < 0; - edge = &aasworld.edges[abs(edgenum)]; - //get the length of the edge - VectorSubtract(aasworld.vertexes[edge->v[1]], - aasworld.vertexes[edge->v[0]], dir); - length = VectorLength(dir); - //get the start point - VectorAdd(aasworld.vertexes[edge->v[0]], - aasworld.vertexes[edge->v[1]], start); - VectorScale(start, 0.5, start); - VectorCopy(start, end); - //get the end point several units inside area2 - //and the start point several units inside area1 - //NOTE: normal is pointing into area2 because the - //face edges are stored counter clockwise - VectorSubtract(aasworld.vertexes[edge->v[side]], - aasworld.vertexes[edge->v[!side]], edgevec); - plane2 = &aasworld.planes[face2->planenum]; - CrossProduct(edgevec, plane2->normal, normal); - VectorNormalize(normal); - // - //VectorMA(start, -1, normal, start); - VectorMA(end, INSIDEUNITS_WALKEND, normal, end); - VectorMA(start, INSIDEUNITS_WALKSTART, normal, start); - end[2] += 0.125; - // - height = DotProduct(invgravity, start); - //NOTE: if there's nearby solid or a gap area after this area - //disabled this crap - //if (AAS_NearbySolidOrGap(start, end)) height += 200; - //NOTE: disabled because it disables reachabilities to very small areas - //if (AAS_PointAreaNum(end) != area2num) continue; - //get the longest lowest edge - if (height < bestheight || - (height < bestheight + 1 && length > bestlength)) - { - bestheight = height; - bestlength = length; - //create a new reachability link - lr.areanum = area2num; - lr.facenum = 0; - lr.edgenum = edgenum; - VectorCopy(start, lr.start); - VectorCopy(end, lr.end); - lr.traveltype = TRAVEL_WALK; - lr.traveltime = 1; - foundreach = qtrue; - } //end if - } //end for - } //end for - } //end for - } //end for - if (foundreach) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = lr.areanum; - lreach->facenum = lr.facenum; - lreach->edgenum = lr.edgenum; - VectorCopy(lr.start, lreach->start); - VectorCopy(lr.end, lreach->end); - lreach->traveltype = lr.traveltype; - lreach->traveltime = lr.traveltime; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //if going into a crouch area - if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) - { - lreach->traveltime += aassettings.rs_startcrouch; - } //end if - /* - //NOTE: if there's nearby solid or a gap area after this area - if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) - { - lreach->traveltime += 100; - } //end if - */ - //avoid rather small areas - //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; - // - reach_equalfloor++; - return qtrue; - } //end if - return qfalse; -} //end of the function AAS_Reachability_EqualFloorHeight -//=========================================================================== -// searches step, barrier, waterjump and walk off ledge reachabilities -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(int area1num, int area2num) -{ - int i, j, k, l, edge1num, edge2num, areas[10], numareas; - int ground_bestarea2groundedgenum, ground_foundreach; - int water_bestarea2groundedgenum, water_foundreach; - int side1, area1swim, faceside1, groundface1num; - float dist, dist1, dist2, diff, invgravitydot, ortdot; - float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y; - float length, ground_bestlength, water_bestlength, ground_bestdist, water_bestdist; - vec3_t v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2; - vec3_t normal, ort, edgevec, start, end, dir; - vec3_t ground_beststart = {0, 0, 0}, ground_bestend = {0, 0, 0}, ground_bestnormal = {0, 0, 0}; - vec3_t water_beststart = {0, 0, 0}, water_bestend = {0, 0, 0}, water_bestnormal = {0, 0, 0}; - vec3_t invgravity = {0, 0, 1}; - vec3_t testpoint; - aas_plane_t *plane; - aas_area_t *area1, *area2; - aas_face_t *groundface1, *groundface2, *ground_bestface1, *water_bestface1; - aas_edge_t *edge1, *edge2; - aas_lreachability_t *lreach; - aas_trace_t trace; - - //must be able to walk or swim in the first area - if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; - // - if (!AAS_AreaGrounded(area2num) && !AAS_AreaSwim(area2num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //if the first area contains a liquid - area1swim = AAS_AreaSwim(area1num); - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + 10) return qfalse; - if (area1->maxs[i] < area2->mins[i] - 10) return qfalse; - } //end for - // - ground_foundreach = qfalse; - ground_bestdist = 99999; - ground_bestlength = 0; - ground_bestarea2groundedgenum = 0; - // - water_foundreach = qfalse; - water_bestdist = 99999; - water_bestlength = 0; - water_bestarea2groundedgenum = 0; - // - for (i = 0; i < area1->numfaces; i++) - { - groundface1num = aasworld.faceindex[area1->firstface + i]; - faceside1 = groundface1num < 0; - groundface1 = &aasworld.faces[abs(groundface1num)]; - //if this isn't a ground face - if (!(groundface1->faceflags & FACE_GROUND)) - { - //if we can swim in the first area - if (area1swim) - { - //face plane must be more or less horizontal - plane = &aasworld.planes[groundface1->planenum ^ (!faceside1)]; - if (DotProduct(plane->normal, invgravity) < 0.7) continue; - } //end if - else - { - //if we can't swim in the area it must be a ground face - continue; - } //end else - } //end if - // - for (k = 0; k < groundface1->numedges; k++) - { - edge1num = aasworld.edgeindex[groundface1->firstedge + k]; - side1 = (edge1num < 0); - //NOTE: for water faces we must take the side area 1 is - // on into account because the face is shared and doesn't - // have to be oriented correctly - if (!(groundface1->faceflags & FACE_GROUND)) side1 = (side1 == faceside1); - edge1num = abs(edge1num); - edge1 = &aasworld.edges[edge1num]; - //vertexes of the edge - VectorCopy(aasworld.vertexes[edge1->v[!side1]], v1); - VectorCopy(aasworld.vertexes[edge1->v[side1]], v2); - //get a vertical plane through the edge - //NOTE: normal is pointing into area 2 because the - //face edges are stored counter clockwise - VectorSubtract(v2, v1, edgevec); - CrossProduct(edgevec, invgravity, normal); - VectorNormalize(normal); - dist = DotProduct(normal, v1); - //check the faces from the second area - for (j = 0; j < area2->numfaces; j++) - { - groundface2 = &aasworld.faces[abs(aasworld.faceindex[area2->firstface + j])]; - //must be a ground face - if (!(groundface2->faceflags & FACE_GROUND)) continue; - //check the edges of this ground face - for (l = 0; l < groundface2->numedges; l++) - { - edge2num = abs(aasworld.edgeindex[groundface2->firstedge + l]); - edge2 = &aasworld.edges[edge2num]; - //vertexes of the edge - VectorCopy(aasworld.vertexes[edge2->v[0]], v3); - VectorCopy(aasworld.vertexes[edge2->v[1]], v4); - //check the distance between the two points and the vertical plane - //through the edge of area1 - diff = DotProduct(normal, v3) - dist; - if (diff < -0.1 || diff > 0.1) continue; - diff = DotProduct(normal, v4) - dist; - if (diff < -0.1 || diff > 0.1) continue; - // - //project the two ground edges into the step side plane - //and calculate the shortest distance between the two - //edges if they overlap in the direction orthogonal to - //the gravity direction - CrossProduct(invgravity, normal, ort); - invgravitydot = DotProduct(invgravity, invgravity); - ortdot = DotProduct(ort, ort); - //projection into the step plane - //NOTE: since gravity is vertical this is just the z coordinate - y1 = v1[2];//DotProduct(v1, invgravity) / invgravitydot; - y2 = v2[2];//DotProduct(v2, invgravity) / invgravitydot; - y3 = v3[2];//DotProduct(v3, invgravity) / invgravitydot; - y4 = v4[2];//DotProduct(v4, invgravity) / invgravitydot; - // - x1 = DotProduct(v1, ort) / ortdot; - x2 = DotProduct(v2, ort) / ortdot; - x3 = DotProduct(v3, ort) / ortdot; - x4 = DotProduct(v4, ort) / ortdot; - // - if (x1 > x2) - { - tmp = x1; x1 = x2; x2 = tmp; - tmp = y1; y1 = y2; y2 = tmp; - VectorCopy(v1, tmpv); VectorCopy(v2, v1); VectorCopy(tmpv, v2); - } //end if - if (x3 > x4) - { - tmp = x3; x3 = x4; x4 = tmp; - tmp = y3; y3 = y4; y4 = tmp; - VectorCopy(v3, tmpv); VectorCopy(v4, v3); VectorCopy(tmpv, v4); - } //end if - //if the two projected edge lines have no overlap - if (x2 <= x3 || x4 <= x1) - { -// Log_Write("lines no overlap: from area %d to %d\r\n", area1num, area2num); - continue; - } //end if - //if the two lines fully overlap - if ((x1 - 0.5 < x3 && x4 < x2 + 0.5) && - (x3 - 0.5 < x1 && x2 < x4 + 0.5)) - { - dist1 = y3 - y1; - dist2 = y4 - y2; - VectorCopy(v1, p1area1); - VectorCopy(v2, p2area1); - VectorCopy(v3, p1area2); - VectorCopy(v4, p2area2); - } //end if - else - { - //if the points are equal - if (x1 > x3 - 0.1 && x1 < x3 + 0.1) - { - dist1 = y3 - y1; - VectorCopy(v1, p1area1); - VectorCopy(v3, p1area2); - } //end if - else if (x1 < x3) - { - y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1); - dist1 = y3 - y; - VectorCopy(v3, p1area1); - p1area1[2] = y; - VectorCopy(v3, p1area2); - } //end if - else - { - y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3); - dist1 = y - y1; - VectorCopy(v1, p1area1); - VectorCopy(v1, p1area2); - p1area2[2] = y; - } //end if - //if the points are equal - if (x2 > x4 - 0.1 && x2 < x4 + 0.1) - { - dist2 = y4 - y2; - VectorCopy(v2, p2area1); - VectorCopy(v4, p2area2); - } //end if - else if (x2 < x4) - { - y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3); - dist2 = y - y2; - VectorCopy(v2, p2area1); - VectorCopy(v2, p2area2); - p2area2[2] = y; - } //end if - else - { - y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1); - dist2 = y4 - y; - VectorCopy(v4, p2area1); - p2area1[2] = y; - VectorCopy(v4, p2area2); - } //end else - } //end else - //if both distances are pretty much equal - //then we take the middle of the points - if (dist1 > dist2 - 1 && dist1 < dist2 + 1) - { - dist = dist1; - VectorAdd(p1area1, p2area1, start); - VectorScale(start, 0.5, start); - VectorAdd(p1area2, p2area2, end); - VectorScale(end, 0.5, end); - } //end if - else if (dist1 < dist2) - { - dist = dist1; - VectorCopy(p1area1, start); - VectorCopy(p1area2, end); - } //end else if - else - { - dist = dist2; - VectorCopy(p2area1, start); - VectorCopy(p2area2, end); - } //end else - //get the length of the overlapping part of the edges of the two areas - VectorSubtract(p2area2, p1area2, dir); - length = VectorLength(dir); - // - if (groundface1->faceflags & FACE_GROUND) - { - //if the vertical distance is smaller - if (dist < ground_bestdist || - //or the vertical distance is pretty much the same - //but the overlapping part of the edges is longer - (dist < ground_bestdist + 1 && length > ground_bestlength)) - { - ground_bestdist = dist; - ground_bestlength = length; - ground_foundreach = qtrue; - ground_bestarea2groundedgenum = edge1num; - ground_bestface1 = groundface1; - //best point towards area1 - VectorCopy(start, ground_beststart); - //normal is pointing into area2 - VectorCopy(normal, ground_bestnormal); - //best point towards area2 - VectorCopy(end, ground_bestend); - } //end if - } //end if - else - { - //if the vertical distance is smaller - if (dist < water_bestdist || - //or the vertical distance is pretty much the same - //but the overlapping part of the edges is longer - (dist < water_bestdist + 1 && length > water_bestlength)) - { - water_bestdist = dist; - water_bestlength = length; - water_foundreach = qtrue; - water_bestarea2groundedgenum = edge1num; - water_bestface1 = groundface1; - //best point towards area1 - VectorCopy(start, water_beststart); - //normal is pointing into area2 - VectorCopy(normal, water_bestnormal); - //best point towards area2 - VectorCopy(end, water_bestend); - } //end if - } //end else - } //end for - } //end for - } //end for - } //end for - // - // NOTE: swim reachabilities are already filtered out - // - // Steps - // - // --------- - // | step height -> TRAVEL_WALK - //--------| - // - // --------- - //~~~~~~~~| step height and low water -> TRAVEL_WALK - //--------| - // - //~~~~~~~~~~~~~~~~~~ - // --------- - // | step height and low water up to the step -> TRAVEL_WALK - //--------| - // - //check for a step reachability - if (ground_foundreach) - { - //if area2 is higher but lower than the maximum step height - //NOTE: ground_bestdist >= 0 also catches equal floor reachabilities - if (ground_bestdist >= 0 && ground_bestdist < aassettings.phys_maxstep) - { - //create walk reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WALK; - lreach->traveltime = 0;//1; - //if going into a crouch area - if (!AAS_AreaCrouch(area1num) && AAS_AreaCrouch(area2num)) - { - lreach->traveltime += aassettings.rs_startcrouch; - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //NOTE: if there's nearby solid or a gap area after this area - /* - if (!AAS_NearbySolidOrGap(lreach->start, lreach->end)) - { - lreach->traveltime += 100; - } //end if - */ - //avoid rather small areas - //if (AAS_AreaGroundFaceArea(lreach->areanum) < 500) lreach->traveltime += 100; - // - reach_step++; - return qtrue; - } //end if - } //end if - // - // Water Jumps - // - // --------- - // | - //~~~~~~~~| - // | - // | higher than step height and water up to waterjump height -> TRAVEL_WATERJUMP - //--------| - // - //~~~~~~~~~~~~~~~~~~ - // --------- - // | - // | - // | - // | higher than step height and low water up to the step -> TRAVEL_WATERJUMP - //--------| - // - //check for a waterjump reachability - if (water_foundreach) - { - //get a test point a little bit towards area1 - VectorMA(water_bestend, -INSIDEUNITS, water_bestnormal, testpoint); - //go down the maximum waterjump height - testpoint[2] -= aassettings.phys_maxwaterjump; - //if there IS water the sv_maxwaterjump height below the bestend point - if (aasworld.areasettings[AAS_PointAreaNum(testpoint)].areaflags & AREA_LIQUID) - { - //don't create rediculous water jump reachabilities from areas very far below - //the water surface - if (water_bestdist < aassettings.phys_maxwaterjump + 24) - { - //waterjumping from or towards a crouch only area is not possible in Quake2 - if ((aasworld.areasettings[area1num].presencetype & PRESENCE_NORMAL) && - (aasworld.areasettings[area2num].presencetype & PRESENCE_NORMAL)) - { - //create water jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = water_bestarea2groundedgenum; - VectorCopy(water_beststart, lreach->start); - VectorMA(water_bestend, INSIDEUNITS_WATERJUMP, water_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WATERJUMP; - lreach->traveltime = aassettings.rs_waterjump; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another waterjump reachability - reach_waterjump++; - return qtrue; - } //end if - } //end if - } //end if - } //end if - // - // Barrier Jumps - // - // --------- - // | - // | - // | - // | higher than step height lower than barrier height -> TRAVEL_BARRIERJUMP - //--------| - // - // --------- - // | - // | - // | - //~~~~~~~~| higher than step height lower than barrier height - //--------| and a thin layer of water in the area to jump from -> TRAVEL_BARRIERJUMP - // - //check for a barrier jump reachability - if (ground_foundreach) - { - //if area2 is higher but lower than the maximum barrier jump height - if (ground_bestdist > 0 && ground_bestdist < aassettings.phys_maxbarrier) - { - //if no water in area1 or a very thin layer of water on the ground - if (!water_foundreach || (ground_bestdist - water_bestdist < 16)) - { - //cannot perform a barrier jump towards or from a crouch area in Quake2 - if (!AAS_AreaCrouch(area1num) && !AAS_AreaCrouch(area2num)) - { - //create barrier jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_BARRIERJUMP; - lreach->traveltime = aassettings.rs_barrierjump;//AAS_BarrierJumpTravelTime(); - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another barrierjump reachability - reach_barrier++; - return qtrue; - } //end if - } //end if - } //end if - } //end if - // - // Walk and Walk Off Ledge - // - //--------| - // | can walk or step back -> TRAVEL_WALK - // --------- - // - //--------| - // | - // | - // | - // | cannot walk/step back -> TRAVEL_WALKOFFLEDGE - // --------- - // - //--------| - // | - // |~~~~~~~~ - // | - // | cannot step back but can waterjump back -> TRAVEL_WALKOFFLEDGE - // --------- FIXME: create TRAVEL_WALK reach?? - // - //check for a walk or walk off ledge reachability - if (ground_foundreach) - { - if (ground_bestdist < 0) - { - if (ground_bestdist > -aassettings.phys_maxstep) - { - //create walk reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorMA(ground_beststart, INSIDEUNITS_WALKSTART, ground_bestnormal, lreach->start); - VectorMA(ground_bestend, INSIDEUNITS_WALKEND, ground_bestnormal, lreach->end); - lreach->traveltype = TRAVEL_WALK; - lreach->traveltime = 1; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //we've got another walk reachability - reach_walk++; - return qtrue; - } //end if - // if no maximum fall height set or less than the max - if (!aassettings.rs_maxfallheight || fabs(ground_bestdist) < aassettings.rs_maxfallheight) { - //trace a bounding box vertically to check for solids - VectorMA(ground_bestend, INSIDEUNITS, ground_bestnormal, ground_bestend); - VectorCopy(ground_bestend, start); - start[2] = ground_beststart[2]; - VectorCopy(ground_bestend, end); - end[2] += 4; - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - //if no solids were found - if (!trace.startsolid && trace.fraction >= 1.0) - { - //the trace end point must be in the goal area - trace.endpos[2] += 1; - if (AAS_PointAreaNum(trace.endpos) == area2num) - { - //if not going through a cluster portal - numareas = AAS_TraceAreas(start, end, areas, NULL, sizeof(areas) / sizeof(int)); - for (i = 0; i < numareas; i++) - if (AAS_AreaClusterPortal(areas[i])) - break; - if (i >= numareas) - { - //create a walk off ledge reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = ground_bestarea2groundedgenum; - VectorCopy(ground_beststart, lreach->start); - VectorCopy(ground_bestend, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(ground_bestdist) * 50 / aassettings.phys_gravity; - //if falling from too high and not falling into water - if (!AAS_AreaSwim(area2num) && !AAS_AreaJumpPad(area2num)) - { - if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - if (AAS_FallDelta(ground_bestdist) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_walkoffledge++; - //NOTE: don't create a weapon (rl, bfg) jump reachability here - //because it interferes with other reachabilities - //like the ladder reachability - return qtrue; - } //end if - } //end if - } //end if - } //end if - } //end else - } //end if - return qfalse; -} //end of the function AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge -//=========================================================================== -// returns the distance between the two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float VectorDistance(vec3_t v1, vec3_t v2) -{ - vec3_t dir; - - VectorSubtract(v2, v1, dir); - return VectorLength(dir); -} //end of the function VectorDistance -//=========================================================================== -// returns true if the first vector is between the last two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int VectorBetweenVectors(vec3_t v, vec3_t v1, vec3_t v2) -{ - vec3_t dir1, dir2; - - VectorSubtract(v, v1, dir1); - VectorSubtract(v, v2, dir2); - return (DotProduct(dir1, dir2) <= 0); -} //end of the function VectorBetweenVectors -//=========================================================================== -// returns the mid point between the two vectors -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void VectorMiddle(vec3_t v1, vec3_t v2, vec3_t middle) -{ - VectorAdd(v1, v2, middle); - VectorScale(middle, 0.5, middle); -} //end of the function VectorMiddle -//=========================================================================== -// calculate a range of points closest to each other on both edges -// -// Parameter: beststart1 start of the range of points on edge v1-v2 -// beststart2 end of the range of points on edge v1-v2 -// bestend1 start of the range of points on edge v3-v4 -// bestend2 end of the range of points on edge v3-v4 -// bestdist best distance so far -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, - aas_plane_t *plane1, aas_plane_t *plane2, - vec3_t beststart, vec3_t bestend, float bestdist) -{ - vec3_t dir1, dir2, p1, p2, p3, p4; - float a1, a2, b1, b2, dist; - int founddist; - - //edge vectors - VectorSubtract(v2, v1, dir1); - VectorSubtract(v4, v3, dir2); - //get the horizontal directions - dir1[2] = 0; - dir2[2] = 0; - // - // p1 = point on an edge vector of area2 closest to v1 - // p2 = point on an edge vector of area2 closest to v2 - // p3 = point on an edge vector of area1 closest to v3 - // p4 = point on an edge vector of area1 closest to v4 - // - if (dir2[0]) - { - a2 = dir2[1] / dir2[0]; - b2 = v3[1] - a2 * v3[0]; - //point on the edge vector of area2 closest to v1 - p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p1[1] = a2 * p1[0] + b2; - //point on the edge vector of area2 closest to v2 - p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p2[1] = a2 * p2[0] + b2; - } //end if - else - { - //point on the edge vector of area2 closest to v1 - p1[0] = v3[0]; - p1[1] = v1[1]; - //point on the edge vector of area2 closest to v2 - p2[0] = v3[0]; - p2[1] = v2[1]; - } //end else - // - if (dir1[0]) - { - // - a1 = dir1[1] / dir1[0]; - b1 = v1[1] - a1 * v1[0]; - //point on the edge vector of area1 closest to v3 - p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p3[1] = a1 * p3[0] + b1; - //point on the edge vector of area1 closest to v4 - p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p4[1] = a1 * p4[0] + b1; - } //end if - else - { - //point on the edge vector of area1 closest to v3 - p3[0] = v1[0]; - p3[1] = v3[1]; - //point on the edge vector of area1 closest to v4 - p4[0] = v1[0]; - p4[1] = v4[1]; - } //end else - //start with zero z-coordinates - p1[2] = 0; - p2[2] = 0; - p3[2] = 0; - p4[2] = 0; - //calculate the z-coordinates from the ground planes - p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; - p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; - p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; - p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; - // - founddist = qfalse; - // - if (VectorBetweenVectors(p1, v3, v4)) - { - dist = VectorDistance(v1, p1); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, v1, beststart); - VectorMiddle(bestend, p1, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(p1, bestend); - } //end if - founddist = qtrue; - } //end if - if (VectorBetweenVectors(p2, v3, v4)) - { - dist = VectorDistance(v2, p2); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, v2, beststart); - VectorMiddle(bestend, p2, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(p2, bestend); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p3, v1, v2)) - { - dist = VectorDistance(v3, p3); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, p3, beststart); - VectorMiddle(bestend, v3, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p3, beststart); - VectorCopy(v3, bestend); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p4, v1, v2)) - { - dist = VectorDistance(v4, p4); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - VectorMiddle(beststart, p4, beststart); - VectorMiddle(bestend, v4, bestend); - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p4, beststart); - VectorCopy(v4, bestend); - } //end if - founddist = qtrue; - } //end else if - //if no shortest distance was found the shortest distance - //is between one of the vertexes of edge1 and one of edge2 - if (!founddist) - { - dist = VectorDistance(v1, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(v3, bestend); - } //end if - dist = VectorDistance(v1, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart); - VectorCopy(v4, bestend); - } //end if - dist = VectorDistance(v2, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(v3, bestend); - } //end if - dist = VectorDistance(v2, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart); - VectorCopy(v4, bestend); - } //end if - } //end if - return bestdist; -} //end of the function AAS_ClosestEdgePoints*/ - -float AAS_ClosestEdgePoints(vec3_t v1, vec3_t v2, vec3_t v3, vec3_t v4, - aas_plane_t *plane1, aas_plane_t *plane2, - vec3_t beststart1, vec3_t bestend1, - vec3_t beststart2, vec3_t bestend2, float bestdist) -{ - vec3_t dir1, dir2, p1, p2, p3, p4; - float a1, a2, b1, b2, dist, dist1, dist2; - int founddist; - - //edge vectors - VectorSubtract(v2, v1, dir1); - VectorSubtract(v4, v3, dir2); - //get the horizontal directions - dir1[2] = 0; - dir2[2] = 0; - // - // p1 = point on an edge vector of area2 closest to v1 - // p2 = point on an edge vector of area2 closest to v2 - // p3 = point on an edge vector of area1 closest to v3 - // p4 = point on an edge vector of area1 closest to v4 - // - if (dir2[0]) - { - a2 = dir2[1] / dir2[0]; - b2 = v3[1] - a2 * v3[0]; - //point on the edge vector of area2 closest to v1 - p1[0] = (DotProduct(v1, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p1[1] = a2 * p1[0] + b2; - //point on the edge vector of area2 closest to v2 - p2[0] = (DotProduct(v2, dir2) - (a2 * dir2[0] + b2 * dir2[1])) / dir2[0]; - p2[1] = a2 * p2[0] + b2; - } //end if - else - { - //point on the edge vector of area2 closest to v1 - p1[0] = v3[0]; - p1[1] = v1[1]; - //point on the edge vector of area2 closest to v2 - p2[0] = v3[0]; - p2[1] = v2[1]; - } //end else - // - if (dir1[0]) - { - // - a1 = dir1[1] / dir1[0]; - b1 = v1[1] - a1 * v1[0]; - //point on the edge vector of area1 closest to v3 - p3[0] = (DotProduct(v3, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p3[1] = a1 * p3[0] + b1; - //point on the edge vector of area1 closest to v4 - p4[0] = (DotProduct(v4, dir1) - (a1 * dir1[0] + b1 * dir1[1])) / dir1[0]; - p4[1] = a1 * p4[0] + b1; - } //end if - else - { - //point on the edge vector of area1 closest to v3 - p3[0] = v1[0]; - p3[1] = v3[1]; - //point on the edge vector of area1 closest to v4 - p4[0] = v1[0]; - p4[1] = v4[1]; - } //end else - //start with zero z-coordinates - p1[2] = 0; - p2[2] = 0; - p3[2] = 0; - p4[2] = 0; - //calculate the z-coordinates from the ground planes - p1[2] = (plane2->dist - DotProduct(plane2->normal, p1)) / plane2->normal[2]; - p2[2] = (plane2->dist - DotProduct(plane2->normal, p2)) / plane2->normal[2]; - p3[2] = (plane1->dist - DotProduct(plane1->normal, p3)) / plane1->normal[2]; - p4[2] = (plane1->dist - DotProduct(plane1->normal, p4)) / plane1->normal[2]; - // - founddist = qfalse; - // - if (VectorBetweenVectors(p1, v3, v4)) - { - dist = VectorDistance(v1, p1); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, v1); - dist2 = VectorDistance(beststart2, v1); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v1, beststart1); - } //end else - dist1 = VectorDistance(bestend1, p1); - dist2 = VectorDistance(bestend2, p1); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p1, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(p1, bestend1); - VectorCopy(p1, bestend2); - } //end if - founddist = qtrue; - } //end if - if (VectorBetweenVectors(p2, v3, v4)) - { - dist = VectorDistance(v2, p2); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, v2); - dist2 = VectorDistance(beststart2, v2); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(v2, beststart1); - } //end else - dist1 = VectorDistance(bestend1, p2); - dist2 = VectorDistance(bestend2, p2); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(p2, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(p2, bestend1); - VectorCopy(p2, bestend2); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p3, v1, v2)) - { - dist = VectorDistance(v3, p3); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, p3); - dist2 = VectorDistance(beststart2, p3); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p3, beststart1); - } //end else - dist1 = VectorDistance(bestend1, v3); - dist2 = VectorDistance(bestend2, v3); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v3, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p3, beststart1); - VectorCopy(p3, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - founddist = qtrue; - } //end else if - if (VectorBetweenVectors(p4, v1, v2)) - { - dist = VectorDistance(v4, p4); - if (dist > bestdist - 0.5 && dist < bestdist + 0.5) - { - dist1 = VectorDistance(beststart1, p4); - dist2 = VectorDistance(beststart2, p4); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart2); - } //end if - else - { - if (dist2 > VectorDistance(beststart1, beststart2)) VectorCopy(p4, beststart1); - } //end else - dist1 = VectorDistance(bestend1, v4); - dist2 = VectorDistance(bestend2, v4); - if (dist1 > dist2) - { - if (dist1 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend2); - } //end if - else - { - if (dist2 > VectorDistance(bestend1, bestend2)) VectorCopy(v4, bestend1); - } //end else - } //end if - else if (dist < bestdist) - { - bestdist = dist; - VectorCopy(p4, beststart1); - VectorCopy(p4, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - founddist = qtrue; - } //end else if - //if no shortest distance was found the shortest distance - //is between one of the vertexes of edge1 and one of edge2 - if (!founddist) - { - dist = VectorDistance(v1, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - dist = VectorDistance(v1, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v1, beststart1); - VectorCopy(v1, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - dist = VectorDistance(v2, v3); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(v3, bestend1); - VectorCopy(v3, bestend2); - } //end if - dist = VectorDistance(v2, v4); - if (dist < bestdist) - { - bestdist = dist; - VectorCopy(v2, beststart1); - VectorCopy(v2, beststart2); - VectorCopy(v4, bestend1); - VectorCopy(v4, bestend2); - } //end if - } //end if - return bestdist; -} //end of the function AAS_ClosestEdgePoints -//=========================================================================== -// creates possible jump reachabilities between the areas -// -// The two closest points on the ground of the areas are calculated -// One of the points will be on an edge of a ground face of area1 and -// one on an edge of a ground face of area2. -// If there is a range of closest points the point in the middle of this range -// is selected. -// Between these two points there must be one or more gaps. -// If the gaps exist a potential jump is predicted. -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Jump(int area1num, int area2num) -{ - int i, j, k, l, face1num, face2num, edge1num, edge2num, traveltype; - int stopevent, areas[10], numareas; - float phys_jumpvel, maxjumpdistance, maxjumpheight, height, bestdist, speed; - vec_t *v1, *v2, *v3, *v4; - vec3_t beststart, beststart2, bestend, bestend2; - vec3_t teststart, testend, dir, velocity, cmdmove, up = {0, 0, 1}, sidewards; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2; - aas_edge_t *edge1, *edge2; - aas_plane_t *plane1, *plane2, *plane; - aas_trace_t trace; - aas_clientmove_t move; - aas_lreachability_t *lreach; - - if (!AAS_AreaGrounded(area1num) || !AAS_AreaGrounded(area2num)) return qfalse; - //cannot jump from or to a crouch area - if (AAS_AreaCrouch(area1num) || AAS_AreaCrouch(area2num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - // - phys_jumpvel = aassettings.phys_jumpvel; - //maximum distance a player can jump - maxjumpdistance = 2 * AAS_MaxJumpDistance(phys_jumpvel); - //maximum height a player can jump with the given initial z velocity - maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); - - //if the areas are not near anough in the x-y direction - for (i = 0; i < 2; i++) - { - if (area1->mins[i] > area2->maxs[i] + maxjumpdistance) return qfalse; - if (area1->maxs[i] < area2->mins[i] - maxjumpdistance) return qfalse; - } //end for - //if area2 is way to high to jump up to - if (area2->mins[2] > area1->maxs[2] + maxjumpheight) return qfalse; - // - bestdist = 999999; - // - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //if not a ground face - if (!(face1->faceflags & FACE_GROUND)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = aasworld.faceindex[area2->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //if not a ground face - if (!(face2->faceflags & FACE_GROUND)) continue; - // - for (k = 0; k < face1->numedges; k++) - { - edge1num = abs(aasworld.edgeindex[face1->firstedge + k]); - edge1 = &aasworld.edges[edge1num]; - for (l = 0; l < face2->numedges; l++) - { - edge2num = abs(aasworld.edgeindex[face2->firstedge + l]); - edge2 = &aasworld.edges[edge2num]; - //calculate the minimum distance between the two edges - v1 = aasworld.vertexes[edge1->v[0]]; - v2 = aasworld.vertexes[edge1->v[1]]; - v3 = aasworld.vertexes[edge2->v[0]]; - v4 = aasworld.vertexes[edge2->v[1]]; - //get the ground planes - plane1 = &aasworld.planes[face1->planenum]; - plane2 = &aasworld.planes[face2->planenum]; - // - bestdist = AAS_ClosestEdgePoints(v1, v2, v3, v4, plane1, plane2, - beststart, bestend, - beststart2, bestend2, bestdist); - } //end for - } //end for - } //end for - } //end for - VectorMiddle(beststart, beststart2, beststart); - VectorMiddle(bestend, bestend2, bestend); - if (bestdist > 4 && bestdist < maxjumpdistance) - { -// Log_Write("shortest distance between %d and %d is %f\r\n", area1num, area2num, bestdist); - // if very close and almost no height difference then the bot can walk - if (bestdist <= 48 && fabs(beststart[2] - bestend[2]) < 8) - { - speed = 400; - traveltype = TRAVEL_WALKOFFLEDGE; - } //end if - else if (AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) - { - //FIXME: why multiply with 1.2??? - speed *= 1.2f; - traveltype = TRAVEL_WALKOFFLEDGE; - } //end else if - else - { - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed (the jump is not possible) then there's no jump reachability created - if (!AAS_HorizontalVelocityForJump(phys_jumpvel, beststart, bestend, &speed)) - return qfalse; - speed *= 1.05f; - traveltype = TRAVEL_JUMP; - // - //NOTE: test if the horizontal distance isn't too small - VectorSubtract(bestend, beststart, dir); - dir[2] = 0; - if (VectorLength(dir) < 10) - return qfalse; - } //end if - // - VectorSubtract(bestend, beststart, dir); - VectorNormalize(dir); - VectorMA(beststart, 1, dir, teststart); - // - VectorCopy(teststart, testend); - testend[2] -= 100; - trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) - return qfalse; - if (trace.fraction < 1) - { - plane = &aasworld.planes[trace.planenum]; - // if the bot can stand on the surface - if (DotProduct(plane->normal, up) >= 0.7) - { - // if no lava or slime below - if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) - { - if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) - return qfalse; - } //end if - } //end if - } //end if - // - VectorMA(bestend, -1, dir, teststart); - // - VectorCopy(teststart, testend); - testend[2] -= 100; - trace = AAS_TraceClientBBox(teststart, testend, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) - return qfalse; - if (trace.fraction < 1) - { - plane = &aasworld.planes[trace.planenum]; - // if the bot can stand on the surface - if (DotProduct(plane->normal, up) >= 0.7) - { - // if no lava or slime below - if (!(AAS_PointContents(trace.endpos) & (CONTENTS_LAVA|CONTENTS_SLIME))) - { - if (teststart[2] - trace.endpos[2] <= aassettings.phys_maxbarrier) - return qfalse; - } //end if - } //end if - } //end if - // - // get command movement - VectorClear(cmdmove); - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) - cmdmove[2] = aassettings.phys_jumpvel; - else - cmdmove[2] = 0; - // - VectorSubtract(bestend, beststart, dir); - dir[2] = 0; - VectorNormalize(dir); - CrossProduct(dir, up, sidewards); - // - stopevent = SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE; - if (!AAS_AreaClusterPortal(area1num) && !AAS_AreaClusterPortal(area2num)) - stopevent |= SE_TOUCHCLUSTERPORTAL; - // - for (i = 0; i < 3; i++) - { - // - if (i == 1) - VectorAdd(testend, sidewards, testend); - else if (i == 2) - VectorSubtract(bestend, sidewards, testend); - else - VectorCopy(bestend, testend); - VectorSubtract(testend, beststart, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorScale(dir, speed, velocity); - // - AAS_PredictClientMovement(&move, -1, beststart, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 3, 30, 0.1f, - stopevent, 0, qfalse); - // if prediction time wasn't enough to fully predict the movement - if (move.frames >= 30) - return qfalse; - // don't enter slime or lava and don't fall from too high - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) - return qfalse; - // never jump or fall through a cluster portal - if (move.stopevent & SE_TOUCHCLUSTERPORTAL) - return qfalse; - //the end position should be in area2, also test a little bit back - //because the predicted jump could have rushed through the area - VectorMA(move.endpos, -64, dir, teststart); - teststart[2] += 1; - numareas = AAS_TraceAreas(move.endpos, teststart, areas, NULL, sizeof(areas) / sizeof(int)); - for (j = 0; j < numareas; j++) - { - if (areas[j] == area2num) - break; - } //end for - if (j < numareas) - break; - } - if (i >= 3) - return qfalse; - // -#ifdef REACH_DEBUG - //create the reachability - Log_Write("jump reachability between %d and %d\r\n", area1num, area2num); -#endif //REACH_DEBUG - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(beststart, lreach->start); - VectorCopy(bestend, lreach->end); - lreach->traveltype = traveltype; - - VectorSubtract(bestend, beststart, dir); - height = dir[2]; - dir[2] = 0; - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE && height > VectorLength(dir)) - { - lreach->traveltime = aassettings.rs_startwalkoffledge + height * 50 / aassettings.phys_gravity; - } - else - { - lreach->traveltime = aassettings.rs_startjump + VectorDistance(bestend, beststart) * 240 / aassettings.phys_maxwalkvelocity; - } //end if - // - if (!AAS_AreaJumpPad(area2num)) - { - if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - else if (AAS_FallDelta(beststart[2] - bestend[2]) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - if ((traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) - reach_jump++; - else - reach_walkoffledge++; - } //end if - return qfalse; -} //end of the function AAS_Reachability_Jump -//=========================================================================== -// create a possible ladder reachability from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Ladder(int area1num, int area2num) -{ - int i, j, k, l, edge1num, edge2num, sharededgenum = 0, lowestedgenum = 0; - int face1num, face2num, ladderface1num = 0, ladderface2num = 0; - int ladderface1vertical, ladderface2vertical, firstv; - float face1area, face2area, bestface1area = -9999, bestface2area = -9999; - float phys_jumpvel, maxjumpheight; - vec3_t area1point, area2point, v1, v2, up = {0, 0, 1}; - vec3_t mid, lowestpoint = {0, 0}, start, end, sharededgevec, dir; - aas_area_t *area1, *area2; - aas_face_t *face1, *face2, *ladderface1 = NULL, *ladderface2 = NULL; - aas_plane_t *plane1, *plane2; - aas_edge_t *sharededge, *edge1; - aas_lreachability_t *lreach; - aas_trace_t trace; - - if (!AAS_AreaLadder(area1num) || !AAS_AreaLadder(area2num)) return qfalse; - // - phys_jumpvel = aassettings.phys_jumpvel; - //maximum height a player can jump with the given initial z velocity - maxjumpheight = AAS_MaxJumpHeight(phys_jumpvel); - - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - - for (i = 0; i < area1->numfaces; i++) - { - face1num = aasworld.faceindex[area1->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //if not a ladder face - if (!(face1->faceflags & FACE_LADDER)) continue; - // - for (j = 0; j < area2->numfaces; j++) - { - face2num = aasworld.faceindex[area2->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //if not a ladder face - if (!(face2->faceflags & FACE_LADDER)) continue; - //check if the faces share an edge - for (k = 0; k < face1->numedges; k++) - { - edge1num = aasworld.edgeindex[face1->firstedge + k]; - for (l = 0; l < face2->numedges; l++) - { - edge2num = aasworld.edgeindex[face2->firstedge + l]; - if (abs(edge1num) == abs(edge2num)) - { - //get the face with the largest area - face1area = AAS_FaceArea(face1); - face2area = AAS_FaceArea(face2); - if (face1area > bestface1area && face2area > bestface2area) - { - bestface1area = face1area; - bestface2area = face2area; - ladderface1 = face1; - ladderface2 = face2; - ladderface1num = face1num; - ladderface2num = face2num; - sharededgenum = edge1num; - } //end if - break; - } //end if - } //end for - if (l != face2->numedges) break; - } //end for - } //end for - } //end for - // - if (ladderface1 && ladderface2) - { - //get the middle of the shared edge - sharededge = &aasworld.edges[abs(sharededgenum)]; - firstv = sharededgenum < 0; - // - VectorCopy(aasworld.vertexes[sharededge->v[firstv]], v1); - VectorCopy(aasworld.vertexes[sharededge->v[!firstv]], v2); - VectorAdd(v1, v2, area1point); - VectorScale(area1point, 0.5, area1point); - VectorCopy(area1point, area2point); - // - //if the face plane in area 1 is pretty much vertical - plane1 = &aasworld.planes[ladderface1->planenum ^ (ladderface1num < 0)]; - plane2 = &aasworld.planes[ladderface2->planenum ^ (ladderface2num < 0)]; - // - //get the points really into the areas - VectorSubtract(v2, v1, sharededgevec); - CrossProduct(plane1->normal, sharededgevec, dir); - VectorNormalize(dir); - //NOTE: 32 because that's larger than 16 (bot bbox x,y) - VectorMA(area1point, -32, dir, area1point); - VectorMA(area2point, 32, dir, area2point); - // - ladderface1vertical = abs(DotProduct(plane1->normal, up)) < 0.1; - ladderface2vertical = abs(DotProduct(plane2->normal, up)) < 0.1; - //there's only reachability between vertical ladder faces - if (!ladderface1vertical && !ladderface2vertical) return qfalse; - //if both vertical ladder faces - if (ladderface1vertical && ladderface2vertical - //and the ladder faces do not make a sharp corner - && DotProduct(plane1->normal, plane2->normal) > 0.7 - //and the shared edge is not too vertical - && abs(DotProduct(sharededgevec, up)) < 0.7) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area1point, lreach->start); - //VectorCopy(area2point, lreach->end); - VectorMA(area2point, -3, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface2num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area2point, lreach->start); - //VectorCopy(area1point, lreach->end); - VectorMA(area1point, -3, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_ladder++; - // - return qtrue; - } //end if - //if the second ladder face is also a ground face - //create ladder end (just ladder) reachability and - //walk off a ladder (ledge) reachability - if (ladderface1vertical && (ladderface2->faceflags & FACE_GROUND)) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area1point, lreach->start); - VectorCopy(area2point, lreach->end); - lreach->end[2] += 16; - VectorMA(lreach->end, -15, plane1->normal, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface2num; - lreach->edgenum = abs(sharededgenum); - VectorCopy(area2point, lreach->start); - VectorCopy(area1point, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_walkoffledge++; - // - return qtrue; - } //end if - // - if (ladderface1vertical) - { - //find lowest edge of the ladder face - lowestpoint[2] = 99999; - for (i = 0; i < ladderface1->numedges; i++) - { - edge1num = abs(aasworld.edgeindex[ladderface1->firstedge + i]); - edge1 = &aasworld.edges[edge1num]; - // - VectorCopy(aasworld.vertexes[edge1->v[0]], v1); - VectorCopy(aasworld.vertexes[edge1->v[1]], v2); - // - VectorAdd(v1, v2, mid); - VectorScale(mid, 0.5, mid); - // - if (mid[2] < lowestpoint[2]) - { - VectorCopy(mid, lowestpoint); - lowestedgenum = edge1num; - } //end if - } //end for - // - plane1 = &aasworld.planes[ladderface1->planenum]; - //trace down in the middle of this edge - VectorMA(lowestpoint, 5, plane1->normal, start); - VectorCopy(start, end); - start[2] += 5; - end[2] -= 100; - //trace without entity collision - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - // - // -#ifdef REACH_DEBUG - if (trace.startsolid) - { - Log_Write("trace from area %d started in solid\r\n", area1num); - } //end if -#endif //REACH_DEBUG - // - trace.endpos[2] += 1; - area2num = AAS_PointAreaNum(trace.endpos); - // - area2 = &aasworld.areas[area2num]; - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - // - if (face2->faceflags & FACE_LADDER) - { - plane2 = &aasworld.planes[face2->planenum]; - if (abs(DotProduct(plane2->normal, up)) < 0.1) break; - } //end if - } //end for - //if from another area without vertical ladder faces - if (i >= area2->numfaces && area2num != area1num && - //the reachabilities shouldn't exist already - !AAS_ReachabilityExists(area1num, area2num) && - !AAS_ReachabilityExists(area2num, area1num)) - { - //if the height is jumpable - if (start[2] - trace.endpos[2] < maxjumpheight) - { - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(lowestpoint, lreach->start); - VectorCopy(trace.endpos, lreach->end); - lreach->traveltype = TRAVEL_LADDER; - lreach->traveltime = 10; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_ladder++; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(trace.endpos, lreach->start); - //get the end point a little bit into the ladder - VectorMA(lowestpoint, -5, plane1->normal, lreach->end); - //get the end point a little higher - lreach->end[2] += 10; - lreach->traveltype = TRAVEL_JUMP; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_jump++; - // - return qtrue; -#ifdef REACH_DEBUG - Log_Write("jump up to ladder reach between %d and %d\r\n", area2num, area1num); -#endif //REACH_DEBUG - } //end if -#ifdef REACH_DEBUG - else Log_Write("jump too high between area %d and %d\r\n", area2num, area1num); -#endif //REACH_DEBUG - } //end if - /*//if slime or lava below the ladder - //try jump reachability from far towards the ladder - if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) - { - for (i = 20; i <= 120; i += 20) - { - //trace down in the middle of this edge - VectorMA(lowestpoint, i, plane1->normal, start); - VectorCopy(start, end); - start[2] += 5; - end[2] -= 100; - //trace without entity collision - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - // - if (trace.startsolid) break; - trace.endpos[2] += 1; - area2num = AAS_PointAreaNum(trace.endpos); - if (area2num == area1num) continue; - // - if (start[2] - trace.endpos[2] > maxjumpheight) continue; - if (aasworld.areasettings[area2num].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) continue; - // - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area1num; - lreach->facenum = ladderface1num; - lreach->edgenum = lowestedgenum; - VectorCopy(trace.endpos, lreach->start); - VectorCopy(lowestpoint, lreach->end); - lreach->end[2] += 5; - lreach->traveltype = TRAVEL_JUMP; - lreach->traveltime = 10; - lreach->next = areareachability[area2num]; - areareachability[area2num] = lreach; - // - reach_jump++; - // - Log_Write("jump far to ladder reach between %d and %d\r\n", area2num, area1num); - // - break; - } //end for - } //end if*/ - } //end if - } //end if - return qfalse; -} //end of the function AAS_Reachability_Ladder -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_TravelFlagsForTeam(int ent) -{ - int notteam; - - if (!AAS_IntForBSPEpairKey(ent, "bot_notteam", ¬team)) - return 0; - if (notteam == 1) - return TRAVELFLAG_NOTTEAM1; - if (notteam == 2) - return TRAVELFLAG_NOTTEAM2; - return 0; -} //end of the function AAS_TravelFlagsForTeam -//=========================================================================== -// create possible teleporter reachabilities -// this is very game dependent.... :( -// -// classname = trigger_multiple or trigger_teleport -// target = "t1" -// -// classname = target_teleporter -// targetname = "t1" -// target = "t2" -// -// classname = misc_teleporter_dest -// targetname = "t2" -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_Teleport(void) -{ - int area1num, area2num; - char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY]; - char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - int ent, dest; - float angle; - vec3_t origin, destorigin, mins, maxs, end, angles; - vec3_t mid, velocity, cmdmove; - aas_lreachability_t *lreach; - aas_clientmove_t move; - aas_trace_t trace; - aas_link_t *areas, *link; - - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "trigger_multiple")) - { - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); -//#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "trigger_multiple model = \"%s\"\n", model); -//#endif REACH_DEBUG - VectorClear(angles); - AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); - // - if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "trigger_multiple at %1.0f %1.0f %1.0f without target\n", - origin[0], origin[1], origin[2]); - continue; - } //end if - for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) - { - if (!AAS_ValueForBSPEpairKey(dest, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "target_teleporter")) - { - if (!AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) - { - break; - } //end if - } //end if - } //end for - if (!dest) - { - continue; - } //end if - if (!AAS_ValueForBSPEpairKey(dest, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "target_teleporter without target\n"); - continue; - } //end if - } //end else - else if (!strcmp(classname, "trigger_teleport")) - { - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); -//#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "trigger_teleport model = \"%s\"\n", model); -//#endif REACH_DEBUG - VectorClear(angles); - AAS_BSPModelMinsMaxsOrigin(atoi(model+1), angles, mins, maxs, origin); - // - if (!AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "trigger_teleport at %1.0f %1.0f %1.0f without target\n", - origin[0], origin[1], origin[2]); - continue; - } //end if - } //end if - else - { - continue; - } //end else - // - for (dest = AAS_NextBSPEntity(0); dest; dest = AAS_NextBSPEntity(dest)) - { - //classname should be misc_teleporter_dest - //but I've also seen target_position and actually any - //entity could be used... burp - if (AAS_ValueForBSPEpairKey(dest, "targetname", targetname, MAX_EPAIRKEY)) - { - if (!strcmp(targetname, target)) - { - break; - } //end if - } //end if - } //end for - if (!dest) - { - botimport.Print(PRT_ERROR, "teleporter without misc_teleporter_dest (%s)\n", target); - continue; - } //end if - if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); - continue; - } //end if - // - area2num = AAS_PointAreaNum(destorigin); - //if not teleported into a teleporter or into a jumppad - if (!AAS_AreaTeleporter(area2num) && !AAS_AreaJumpPad(area2num)) - { - VectorCopy(destorigin, end); - end[2] -= 64; - trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); - continue; - } //end if - area2num = AAS_PointAreaNum(trace.endpos); - // - /* - if (!AAS_AreaTeleporter(area2num) && - !AAS_AreaJumpPad(area2num) && - !AAS_AreaGrounded(area2num)) - { - VectorCopy(trace.endpos, destorigin); - } - else*/ - { - //predict where you'll end up - AAS_FloatForBSPEpairKey(dest, "angle", &angle); - if (angle) - { - VectorSet(angles, 0, angle, 0); - AngleVectors(angles, velocity, NULL, NULL); - VectorScale(velocity, 400, velocity); - } //end if - else - { - VectorClear(velocity); - } //end else - VectorClear(cmdmove); - AAS_PredictClientMovement(&move, -1, destorigin, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, - SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, qfalse); //qtrue); - area2num = AAS_PointAreaNum(move.endpos); - if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA)) - { - botimport.Print(PRT_WARNING, "teleported into slime or lava at dest %s\n", target); - } //end if - VectorCopy(move.endpos, destorigin); - } //end else - } //end if - // - //botimport.Print(PRT_MESSAGE, "teleporter brush origin at %f %f %f\n", origin[0], origin[1], origin[2]); - //botimport.Print(PRT_MESSAGE, "teleporter brush mins = %f %f %f\n", mins[0], mins[1], mins[2]); - //botimport.Print(PRT_MESSAGE, "teleporter brush maxs = %f %f %f\n", maxs[0], maxs[1], maxs[2]); - VectorAdd(origin, mins, mins); - VectorAdd(origin, maxs, maxs); - // - VectorAdd(mins, maxs, mid); - VectorScale(mid, 0.5, mid); - //link an invalid (-1) entity - areas = AAS_LinkEntityClientBBox(mins, maxs, -1, PRESENCE_CROUCH); - if (!areas) botimport.Print(PRT_MESSAGE, "trigger_multiple not in any area\n"); - // - for (link = areas; link; link = link->next_area) - { - //if (!AAS_AreaGrounded(link->areanum)) continue; - if (!AAS_AreaTeleporter(link->areanum)) continue; - // - area1num = link->areanum; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) break; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(mid, lreach->start); - VectorCopy(destorigin, lreach->end); - lreach->traveltype = TRAVEL_TELEPORT; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_teleport; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_teleport++; - } //end for - //unlink the invalid entity - AAS_UnlinkFromAreas(areas); - } //end for -} //end of the function AAS_Reachability_Teleport -//=========================================================================== -// create possible elevator (func_plat) reachabilities -// this is very game dependent.... :( -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_Elevator(void) -{ - int area1num, area2num, modelnum, i, j, k, l, n, p; - float lip, height, speed; - char model[MAX_EPAIRKEY], classname[MAX_EPAIRKEY]; - int ent; - vec3_t mins, maxs, origin, angles = {0, 0, 0}; - vec3_t pos1, pos2, mids, platbottom, plattop; - vec3_t bottomorg, toporg, start, end, dir; - vec_t xvals[8], yvals[8], xvals_top[8], yvals_top[8]; - aas_lreachability_t *lreach; - aas_trace_t trace; - -#ifdef REACH_DEBUG - Log_Write("AAS_Reachability_Elevator\r\n"); -#endif //REACH_DEBUG - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (!strcmp(classname, "func_plat")) - { -#ifdef REACH_DEBUG - Log_Write("found func plat\r\n"); -#endif //REACH_DEBUG - if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "func_plat without model\n"); - continue; - } //end if - //get the model number, and skip the leading * - modelnum = atoi(model+1); - if (modelnum <= 0) - { - botimport.Print(PRT_ERROR, "func_plat with invalid model number\n"); - continue; - } //end if - //get the mins, maxs and origin of the model - //NOTE: the origin is usually (0,0,0) and the mins and maxs - // are the absolute mins and maxs - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); - // - AAS_VectorForBSPEpairKey(ent, "origin", origin); - //pos1 is the top position, pos2 is the bottom - VectorCopy(origin, pos1); - VectorCopy(origin, pos2); - //get the lip of the plat - AAS_FloatForBSPEpairKey(ent, "lip", &lip); - if (!lip) lip = 8; - //get the movement height of the plat - AAS_FloatForBSPEpairKey(ent, "height", &height); - if (!height) height = (maxs[2] - mins[2]) - lip; - //get the speed of the plat - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 200; - //get bottom position below pos1 - pos2[2] -= height; - // - //get a point just above the plat in the bottom position - VectorAdd(mins, maxs, mids); - VectorMA(pos2, 0.5, mids, platbottom); - platbottom[2] = maxs[2] - (pos1[2] - pos2[2]) + 2; - //get a point just above the plat in the top position - VectorAdd(mins, maxs, mids); - VectorMA(pos2, 0.5, mids, plattop); - plattop[2] = maxs[2] + 2; - // - /*if (!area1num) - { - Log_Write("no grounded area near plat bottom\r\n"); - continue; - } //end if*/ - //get the mins and maxs a little larger - for (i = 0; i < 3; i++) - { - mins[i] -= 1; - maxs[i] += 1; - } //end for - // - //botimport.Print(PRT_MESSAGE, "platbottom[2] = %1.1f plattop[2] = %1.1f\n", platbottom[2], plattop[2]); - // - VectorAdd(mins, maxs, mids); - VectorScale(mids, 0.5, mids); - // - xvals[0] = mins[0]; xvals[1] = mids[0]; xvals[2] = maxs[0]; xvals[3] = mids[0]; - yvals[0] = mids[1]; yvals[1] = maxs[1]; yvals[2] = mids[1]; yvals[3] = mins[1]; - // - xvals[4] = mins[0]; xvals[5] = maxs[0]; xvals[6] = maxs[0]; xvals[7] = mins[0]; - yvals[4] = maxs[1]; yvals[5] = maxs[1]; yvals[6] = mins[1]; yvals[7] = mins[1]; - //find adjacent areas around the bottom of the plat - for (i = 0; i < 9; i++) - { - if (i < 8) //check at the sides of the plat - { - bottomorg[0] = origin[0] + xvals[i]; - bottomorg[1] = origin[1] + yvals[i]; - bottomorg[2] = platbottom[2] + 16; - //get a grounded or swim area near the plat in the bottom position - area1num = AAS_PointAreaNum(bottomorg); - for (k = 0; k < 16; k++) - { - if (area1num) - { - if (AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) break; - } //end if - bottomorg[2] += 4; - area1num = AAS_PointAreaNum(bottomorg); - } //end if - //if in solid - if (k >= 16) - { - continue; - } //end if - } //end if - else //at the middle of the plat - { - VectorCopy(plattop, bottomorg); - bottomorg[2] += 24; - area1num = AAS_PointAreaNum(bottomorg); - if (!area1num) continue; - VectorCopy(platbottom, bottomorg); - bottomorg[2] += 24; - } //end else - //look at adjacent areas around the top of the plat - //make larger steps to outside the plat everytime - for (n = 0; n < 3; n++) - { - for (k = 0; k < 3; k++) - { - mins[k] -= 4; - maxs[k] += 4; - } //end for - xvals_top[0] = mins[0]; xvals_top[1] = mids[0]; xvals_top[2] = maxs[0]; xvals_top[3] = mids[0]; - yvals_top[0] = mids[1]; yvals_top[1] = maxs[1]; yvals_top[2] = mids[1]; yvals_top[3] = mins[1]; - // - xvals_top[4] = mins[0]; xvals_top[5] = maxs[0]; xvals_top[6] = maxs[0]; xvals_top[7] = mins[0]; - yvals_top[4] = maxs[1]; yvals_top[5] = maxs[1]; yvals_top[6] = mins[1]; yvals_top[7] = mins[1]; - // - for (j = 0; j < 8; j++) - { - toporg[0] = origin[0] + xvals_top[j]; - toporg[1] = origin[1] + yvals_top[j]; - toporg[2] = plattop[2] + 16; - //get a grounded or swim area near the plat in the top position - area2num = AAS_PointAreaNum(toporg); - for (l = 0; l < 16; l++) - { - if (area2num) - { - if (AAS_AreaGrounded(area2num) || AAS_AreaSwim(area2num)) - { - VectorCopy(plattop, start); - start[2] += 32; - VectorCopy(toporg, end); - end[2] += 1; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.fraction >= 1) break; - } //end if - } //end if - toporg[2] += 4; - area2num = AAS_PointAreaNum(toporg); - } //end if - //if in solid - if (l >= 16) continue; - //never create a reachability in the same area - if (area2num == area1num) continue; - //if the area isn't grounded - if (!AAS_AreaGrounded(area2num)) continue; - //if there already exists reachability between the areas - if (AAS_ReachabilityExists(area1num, area2num)) continue; - //if the reachability start is within the elevator bounding box - VectorSubtract(bottomorg, platbottom, dir); - VectorNormalize(dir); - dir[0] = bottomorg[0] + 24 * dir[0]; - dir[1] = bottomorg[1] + 24 * dir[1]; - dir[2] = bottomorg[2]; - // - for (p = 0; p < 3; p++) - if (dir[p] < origin[p] + mins[p] || dir[p] > origin[p] + maxs[p]) break; - if (p >= 3) continue; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) continue; - lreach->areanum = area2num; - //the facenum is the model number - lreach->facenum = modelnum; - //the edgenum is the height - lreach->edgenum = (int) height; - // - VectorCopy(dir, lreach->start); - VectorCopy(toporg, lreach->end); - lreach->traveltype = TRAVEL_ELEVATOR; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_startelevator + height * 100 / speed; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - //don't go any further to the outside - n = 9999; - // -#ifdef REACH_DEBUG - Log_Write("elevator reach from %d to %d\r\n", area1num, area2num); -#endif //REACH_DEBUG - // - reach_elevator++; - } //end for - } //end for - } //end for - } //end if - } //end for -} //end of the function AAS_Reachability_Elevator -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -aas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoints, aas_plane_t *plane, int towardsface) -{ - int i, j, k, l; - int facenum, edgenum, bestfacenum; - float *v1, *v2, *v3, *v4; - float bestdist, speed, hordist, dist; - vec3_t beststart, beststart2, bestend, bestend2, tmp, hordir, testpoint; - aas_lreachability_t *lreach, *lreachabilities; - aas_area_t *area; - aas_face_t *face; - aas_edge_t *edge; - aas_plane_t *faceplane, *bestfaceplane; - - // - lreachabilities = NULL; - bestfacenum = 0; - bestfaceplane = NULL; - // - for (i = 1; i < aasworld.numareas; i++) - { - area = &aasworld.areas[i]; - // get the shortest distance between one of the func_bob start edges and - // one of the face edges of area1 - bestdist = 999999; - for (j = 0; j < area->numfaces; j++) - { - facenum = aasworld.faceindex[area->firstface + j]; - face = &aasworld.faces[abs(facenum)]; - //if not a ground face - if (!(face->faceflags & FACE_GROUND)) continue; - //get the ground planes - faceplane = &aasworld.planes[face->planenum]; - // - for (k = 0; k < face->numedges; k++) - { - edgenum = abs(aasworld.edgeindex[face->firstedge + k]); - edge = &aasworld.edges[edgenum]; - //calculate the minimum distance between the two edges - v1 = aasworld.vertexes[edge->v[0]]; - v2 = aasworld.vertexes[edge->v[1]]; - // - for (l = 0; l < numpoints; l++) - { - v3 = facepoints[l]; - v4 = facepoints[(l+1) % numpoints]; - dist = AAS_ClosestEdgePoints(v1, v2, v3, v4, faceplane, plane, - beststart, bestend, - beststart2, bestend2, bestdist); - if (dist < bestdist) - { - bestfacenum = facenum; - bestfaceplane = faceplane; - bestdist = dist; - } //end if - } //end for - } //end for - } //end for - // - if (bestdist > 192) continue; - // - VectorMiddle(beststart, beststart2, beststart); - VectorMiddle(bestend, bestend2, bestend); - // - if (!towardsface) - { - VectorCopy(beststart, tmp); - VectorCopy(bestend, beststart); - VectorCopy(tmp, bestend); - } //end if - // - VectorSubtract(bestend, beststart, hordir); - hordir[2] = 0; - hordist = VectorLength(hordir); - // - if (hordist > 2 * AAS_MaxJumpDistance(aassettings.phys_jumpvel)) continue; - //the end point should not be significantly higher than the start point - if (bestend[2] - 32 > beststart[2]) continue; - //don't fall down too far - if (bestend[2] < beststart[2] - 128) continue; - //the distance should not be too far - if (hordist > 32) - { - //check for walk off ledge - if (!AAS_HorizontalVelocityForJump(0, beststart, bestend, &speed)) continue; - } //end if - // - beststart[2] += 1; - bestend[2] += 1; - // - if (towardsface) VectorCopy(bestend, testpoint); - else VectorCopy(beststart, testpoint); - testpoint[2] = 0; - testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2]; - // - if (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f)) - { - //if the faces are not overlapping then only go down - if (bestend[2] - 16 > beststart[2]) continue; - } //end if - lreach = AAS_AllocReachability(); - if (!lreach) return lreachabilities; - lreach->areanum = i; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(beststart, lreach->start); - VectorCopy(bestend, lreach->end); - lreach->traveltype = 0; - lreach->traveltime = 0; - lreach->next = lreachabilities; - lreachabilities = lreach; -#ifndef BSPC - if (towardsface) AAS_PermanentLine(lreach->start, lreach->end, 1); - else AAS_PermanentLine(lreach->start, lreach->end, 2); -#endif - } //end for - return lreachabilities; -} //end of the function AAS_FindFaceReachabilities -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_FuncBobbing(void) -{ - int ent, spawnflags, modelnum, axis; - int i, numareas, areas[10]; - char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - vec3_t origin, move_end, move_start, move_start_top, move_end_top; - vec3_t mins, maxs, angles = {0, 0, 0}; - vec3_t start_edgeverts[4], end_edgeverts[4], mid; - vec3_t org, start, end, dir, points[10]; - float height; - aas_plane_t start_plane, end_plane; - aas_lreachability_t *startreach, *endreach, *nextstartreach, *nextendreach, *lreach; - aas_lreachability_t *firststartreach, *firstendreach; - - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "func_bobbing")) continue; - AAS_FloatForBSPEpairKey(ent, "height", &height); - if (!height) height = 32; - // - if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) - { - botimport.Print(PRT_ERROR, "func_bobbing without model\n"); - continue; - } //end if - //get the model number, and skip the leading * - modelnum = atoi(model+1); - if (modelnum <= 0) - { - botimport.Print(PRT_ERROR, "func_bobbing with invalid model number\n"); - continue; - } //end if - //if the entity has an origin set then use it - if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) - VectorSet(origin, 0, 0, 0); - // - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); - // - VectorAdd(mins, origin, mins); - VectorAdd(maxs, origin, maxs); - // - VectorAdd(mins, maxs, mid); - VectorScale(mid, 0.5, mid); - VectorCopy(mid, origin); - // - VectorCopy(origin, move_end); - VectorCopy(origin, move_start); - // - AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - // set the axis of bobbing - if (spawnflags & 1) axis = 0; - else if (spawnflags & 2) axis = 1; - else axis = 2; - // - move_start[axis] -= height; - move_end[axis] += height; - // - Log_Write("funcbob model %d, start = {%1.1f, %1.1f, %1.1f} end = {%1.1f, %1.1f, %1.1f}\n", - modelnum, move_start[0], move_start[1], move_start[2], move_end[0], move_end[1], move_end[2]); - // -#ifndef BSPC - /* - AAS_DrawPermanentCross(move_start, 4, 1); - AAS_DrawPermanentCross(move_end, 4, 2); - */ -#endif - // - for (i = 0; i < 4; i++) - { - VectorCopy(move_start, start_edgeverts[i]); - start_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z - start_edgeverts[i][2] += 24; //+ player origin to ground dist - } //end for - start_edgeverts[0][0] += maxs[0] - mid[0]; - start_edgeverts[0][1] += maxs[1] - mid[1]; - start_edgeverts[1][0] += maxs[0] - mid[0]; - start_edgeverts[1][1] += mins[1] - mid[1]; - start_edgeverts[2][0] += mins[0] - mid[0]; - start_edgeverts[2][1] += mins[1] - mid[1]; - start_edgeverts[3][0] += mins[0] - mid[0]; - start_edgeverts[3][1] += maxs[1] - mid[1]; - // - start_plane.dist = start_edgeverts[0][2]; - VectorSet(start_plane.normal, 0, 0, 1); - // - for (i = 0; i < 4; i++) - { - VectorCopy(move_end, end_edgeverts[i]); - end_edgeverts[i][2] += maxs[2] - mid[2]; //+ bbox maxs z - end_edgeverts[i][2] += 24; //+ player origin to ground dist - } //end for - end_edgeverts[0][0] += maxs[0] - mid[0]; - end_edgeverts[0][1] += maxs[1] - mid[1]; - end_edgeverts[1][0] += maxs[0] - mid[0]; - end_edgeverts[1][1] += mins[1] - mid[1]; - end_edgeverts[2][0] += mins[0] - mid[0]; - end_edgeverts[2][1] += mins[1] - mid[1]; - end_edgeverts[3][0] += mins[0] - mid[0]; - end_edgeverts[3][1] += maxs[1] - mid[1]; - // - end_plane.dist = end_edgeverts[0][2]; - VectorSet(end_plane.normal, 0, 0, 1); - // -#ifndef BSPC -#if 0 - for (i = 0; i < 4; i++) - { - AAS_PermanentLine(start_edgeverts[i], start_edgeverts[(i+1)%4], 1); - AAS_PermanentLine(end_edgeverts[i], end_edgeverts[(i+1)%4], 1); - } //end for -#endif -#endif - VectorCopy(move_start, move_start_top); - move_start_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z - VectorCopy(move_end, move_end_top); - move_end_top[2] += maxs[2] - mid[2] + 24; //+ bbox maxs z - // - if (!AAS_PointAreaNum(move_start_top)) continue; - if (!AAS_PointAreaNum(move_end_top)) continue; - // - for (i = 0; i < 2; i++) - { - firststartreach = firstendreach = NULL; - // - if (i == 0) - { - firststartreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qtrue); - firstendreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qfalse); - } //end if - else - { - firststartreach = AAS_FindFaceReachabilities(end_edgeverts, 4, &end_plane, qtrue); - firstendreach = AAS_FindFaceReachabilities(start_edgeverts, 4, &start_plane, qfalse); - } //end else - // - //create reachabilities from start to end - for (startreach = firststartreach; startreach; startreach = nextstartreach) - { - nextstartreach = startreach->next; - // - //trace = AAS_TraceClientBBox(startreach->start, move_start_top, PRESENCE_NORMAL, -1); - //if (trace.fraction < 1) continue; - // - for (endreach = firstendreach; endreach; endreach = nextendreach) - { - nextendreach = endreach->next; - // - //trace = AAS_TraceClientBBox(endreach->end, move_end_top, PRESENCE_NORMAL, -1); - //if (trace.fraction < 1) continue; - // - Log_Write("funcbob reach from area %d to %d\n", startreach->areanum, endreach->areanum); - // - // - if (i == 0) VectorCopy(move_start_top, org); - else VectorCopy(move_end_top, org); - VectorSubtract(startreach->start, org, dir); - dir[2] = 0; - VectorNormalize(dir); - VectorCopy(startreach->start, start); - VectorMA(startreach->start, 1, dir, start); - start[2] += 1; - VectorMA(startreach->start, 16, dir, end); - end[2] += 1; - // - numareas = AAS_TraceAreas(start, end, areas, points, 10); - if (numareas <= 0) continue; - if (numareas > 1) VectorCopy(points[1], startreach->start); - else VectorCopy(end, startreach->start); - // - if (!AAS_PointAreaNum(startreach->start)) continue; - if (!AAS_PointAreaNum(endreach->end)) continue; - // - lreach = AAS_AllocReachability(); - lreach->areanum = endreach->areanum; - if (i == 0) lreach->edgenum = ((int)move_start[axis] << 16) | ((int) move_end[axis] & 0x0000ffff); - else lreach->edgenum = ((int)move_end[axis] << 16) | ((int) move_start[axis] & 0x0000ffff); - lreach->facenum = (spawnflags << 16) | modelnum; - VectorCopy(startreach->start, lreach->start); - VectorCopy(endreach->end, lreach->end); -#ifndef BSPC -// AAS_DrawArrow(lreach->start, lreach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); -// AAS_PermanentLine(lreach->start, lreach->end, 1); -#endif - lreach->traveltype = TRAVEL_FUNCBOB; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_funcbob; - reach_funcbob++; - lreach->next = areareachability[startreach->areanum]; - areareachability[startreach->areanum] = lreach; - // - } //end for - } //end for - for (startreach = firststartreach; startreach; startreach = nextstartreach) - { - nextstartreach = startreach->next; - AAS_FreeReachability(startreach); - } //end for - for (endreach = firstendreach; endreach; endreach = nextendreach) - { - nextendreach = endreach->next; - AAS_FreeReachability(endreach); - } //end for - //only go up with func_bobbing entities that go up and down - if (!(spawnflags & 1) && !(spawnflags & 2)) break; - } //end for - } //end for -} //end of the function AAS_Reachability_FuncBobbing -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_JumpPad(void) -{ - int face2num, i, ret, area2num, visualize, ent, bot_visualizejumppads; - //int modelnum, ent2; - //float dist, time, height, gravity, forward; - float speed, zvel, hordist; - aas_face_t *face2; - aas_area_t *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, dir, cmdmove; - vec3_t velocity, absmins, absmaxs; - //vec3_t origin, ent2origin, angles, teststart; - aas_clientmove_t move; - //aas_trace_t trace; - aas_link_t *areas, *link; - //char target[MAX_EPAIRKEY], targetname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; - char classname[MAX_EPAIRKEY]; - -#ifdef BSPC - bot_visualizejumppads = 0; -#else - bot_visualizejumppads = LibVarValue("bot_visualizejumppads", "0"); -#endif - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if (strcmp(classname, "trigger_push")) continue; - // - if (!AAS_GetJumpPadInfo(ent, areastart, absmins, absmaxs, velocity)) continue; - /* - // - AAS_FloatForBSPEpairKey(ent, "speed", &speed); - if (!speed) speed = 1000; -// AAS_VectorForBSPEpairKey(ent, "angles", angles); -// AAS_SetMovedir(angles, velocity); -// VectorScale(velocity, speed, velocity); - VectorClear(angles); - //get the mins, maxs and origin of the model - AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY); - if (model[0]) modelnum = atoi(model+1); - else modelnum = 0; - AAS_BSPModelMinsMaxsOrigin(modelnum, angles, absmins, absmaxs, origin); - VectorAdd(origin, absmins, absmins); - VectorAdd(origin, absmaxs, absmaxs); - // -#ifdef REACH_DEBUG - botimport.Print(PRT_MESSAGE, "absmins = %f %f %f\n", absmins[0], absmins[1], absmins[2]); - botimport.Print(PRT_MESSAGE, "absmaxs = %f %f %f\n", absmaxs[0], absmaxs[1], absmaxs[2]); -#endif REACH_DEBUG - VectorAdd(absmins, absmaxs, origin); - VectorScale (origin, 0.5, origin); - - //get the start areas - VectorCopy(origin, teststart); - teststart[2] += 64; - trace = AAS_TraceClientBBox(teststart, origin, PRESENCE_CROUCH, -1); - if (trace.startsolid) - { - botimport.Print(PRT_MESSAGE, "trigger_push start solid\n"); - VectorCopy(origin, areastart); - } //end if - else - { - VectorCopy(trace.endpos, areastart); - } //end else - areastart[2] += 0.125; - // - //AAS_DrawPermanentCross(origin, 4, 4); - //get the target entity - AAS_ValueForBSPEpairKey(ent, "target", target, MAX_EPAIRKEY); - for (ent2 = AAS_NextBSPEntity(0); ent2; ent2 = AAS_NextBSPEntity(ent2)) - { - if (!AAS_ValueForBSPEpairKey(ent2, "targetname", targetname, MAX_EPAIRKEY)) continue; - if (!strcmp(targetname, target)) break; - } //end for - if (!ent2) - { - botimport.Print(PRT_MESSAGE, "trigger_push without target entity %s\n", target); - continue; - } //end if - AAS_VectorForBSPEpairKey(ent2, "origin", ent2origin); - // - height = ent2origin[2] - origin[2]; - gravity = aassettings.sv_gravity; - time = sqrt( height / ( 0.5 * gravity ) ); - if (!time) - { - botimport.Print(PRT_MESSAGE, "trigger_push without time\n"); - continue; - } //end if - // set s.origin2 to the push velocity - VectorSubtract ( ent2origin, origin, velocity); - dist = VectorNormalize( velocity); - forward = dist / time; - //FIXME: why multiply by 1.1 - forward *= 1.1; - VectorScale(velocity, forward, velocity); - velocity[2] = time * gravity; - */ - //get the areas the jump pad brush is in - areas = AAS_LinkEntityClientBBox(absmins, absmaxs, -1, PRESENCE_CROUCH); - /* - for (link = areas; link; link = link->next_area) - { - if (link->areanum == 563) - { - ret = qfalse; - } - } - */ - for (link = areas; link; link = link->next_area) - { - if (AAS_AreaJumpPad(link->areanum)) break; - } //end for - if (!link) - { - botimport.Print(PRT_MESSAGE, "trigger_push not in any jump pad area\n"); - AAS_UnlinkFromAreas(areas); - continue; - } //end if - // - botimport.Print(PRT_MESSAGE, "found a trigger_push with velocity %f %f %f\n", velocity[0], velocity[1], velocity[2]); - //if there is a horizontal velocity check for a reachability without air control - if (velocity[0] || velocity[1]) - { - VectorSet(cmdmove, 0, 0, 0); - //VectorCopy(velocity, cmdmove); - //cmdmove[2] = 0; - Com_Memset(&move, 0, sizeof(aas_clientmove_t)); - area2num = 0; - for (i = 0; i < 20; i++) - { - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 0, 30, 0.1f, - SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER, 0, bot_visualizejumppads); - area2num = move.endarea; - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (link->areanum == area2num) break; - } //end if - if (!link) break; - VectorCopy(move.endpos, areastart); - VectorCopy(move.velocity, velocity); - } //end for - if (area2num && i < 20) - { - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (AAS_ReachabilityExists(link->areanum, area2num)) continue; - //create a rocket or bfg jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) - { - AAS_UnlinkFromAreas(areas); - return; - } //end if - lreach->areanum = area2num; - //NOTE: the facenum is the Z velocity - lreach->facenum = velocity[2]; - //NOTE: the edgenum is the horizontal velocity - lreach->edgenum = sqrt(velocity[0] * velocity[0] + velocity[1] * velocity[1]); - VectorCopy(areastart, lreach->start); - VectorCopy(move.endpos, lreach->end); - lreach->traveltype = TRAVEL_JUMPPAD; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_jumppad; - lreach->next = areareachability[link->areanum]; - areareachability[link->areanum] = lreach; - // - reach_jumppad++; - } //end for - } //end if - } //end if - // - if (fabs(velocity[0]) > 100 || fabs(velocity[1]) > 100) continue; - //check for areas we can reach with air control - for (area2num = 1; area2num < aasworld.numareas; area2num++) - { - visualize = qfalse; - /* - if (area2num == 3568) - { - for (link = areas; link; link = link->next_area) - { - if (link->areanum == 3380) - { - visualize = qtrue; - botimport.Print(PRT_MESSAGE, "bah\n"); - } //end if - } //end for - } //end if*/ - //never try to go back to one of the original jumppad areas - //and don't create reachabilities if they already exist - for (link = areas; link; link = link->next_area) - { - if (AAS_ReachabilityExists(link->areanum, area2num)) break; - if (AAS_AreaJumpPad(link->areanum)) - { - if (link->areanum == area2num) break; - } //end if - } //end if - if (link) continue; - // - area2 = &aasworld.areas[area2num]; - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a ground face - if (!(face2->faceflags & FACE_GROUND)) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up - if (facecenter[2] < areastart[2]) continue; - //get the jumppad jump z velocity - zvel = velocity[2]; - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed - ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); - if (ret && speed < 150) - { - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - dir[2] = 0; - hordist = VectorNormalize(dir); - //if (hordist < 1.6 * facecenter[2] - areastart[2]) - { - //get command movement - VectorScale(dir, speed, cmdmove); - // - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qfalse, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER|SE_HITGROUNDAREA, area2num, visualize); - //if prediction time wasn't enough to fully predict the movement - //don't enter slime or lava and don't fall from too high - if (move.frames < 30 && - !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD|SE_TOUCHTELEPORTER))) - { - //never go back to the same jumppad - for (link = areas; link; link = link->next_area) - { - if (link->areanum == move.endarea) break; - } - if (!link) - { - for (link = areas; link; link = link->next_area) - { - if (!AAS_AreaJumpPad(link->areanum)) continue; - if (AAS_ReachabilityExists(link->areanum, area2num)) continue; - //create a jumppad reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) - { - AAS_UnlinkFromAreas(areas); - return; - } //end if - lreach->areanum = move.endarea; - //NOTE: the facenum is the Z velocity - lreach->facenum = velocity[2]; - //NOTE: the edgenum is the horizontal velocity - lreach->edgenum = sqrt(cmdmove[0] * cmdmove[0] + cmdmove[1] * cmdmove[1]); - VectorCopy(areastart, lreach->start); - VectorCopy(facecenter, lreach->end); - lreach->traveltype = TRAVEL_JUMPPAD; - lreach->traveltype |= AAS_TravelFlagsForTeam(ent); - lreach->traveltime = aassettings.rs_aircontrolledjumppad; - lreach->next = areareachability[link->areanum]; - areareachability[link->areanum] = lreach; - // - reach_jumppad++; - } //end for - } - } //end if - } //end if - } //end for - } //end for - } //end for - AAS_UnlinkFromAreas(areas); - } //end for -} //end of the function AAS_Reachability_JumpPad -//=========================================================================== -// never point at ground faces -// always a higher and pretty far area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_Grapple(int area1num, int area2num) -{ - int face2num, i, j, areanum, numareas, areas[20]; - float mingrappleangle, z, hordist; - bsp_trace_t bsptrace; - aas_trace_t trace; - aas_face_t *face2; - aas_area_t *area1, *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1}; - vec_t *v; - - //only grapple when on the ground or swimming - if (!AAS_AreaGrounded(area1num) && !AAS_AreaSwim(area1num)) return qfalse; - //don't grapple from a crouch area - if (!(AAS_AreaPresenceType(area1num) & PRESENCE_NORMAL)) return qfalse; - //NOTE: disabled area swim it doesn't work right - if (AAS_AreaSwim(area1num)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //don't grapple towards way lower areas - if (area2->maxs[2] < area1->mins[2]) return qfalse; - // - VectorCopy(aasworld.areas[area1num].center, start); - //if not a swim area - if (!AAS_AreaSwim(area1num)) - { - if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, - start[0], start[1], start[2]); - VectorCopy(start, end); - end[2] -= 1000; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) return qfalse; - VectorCopy(trace.endpos, areastart); - } //end if - else - { - if (!(AAS_PointContents(start) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return qfalse; - } //end else - // - //start is now the start point - // - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a solid face - if (!(face2->faceflags & FACE_SOLID)) continue; - //direction towards the first vertex of the face - v = aasworld.vertexes[aasworld.edges[abs(aasworld.edgeindex[face2->firstedge])].v[0]]; - VectorSubtract(v, areastart, dir); - //if the face plane is facing away - if (DotProduct(aasworld.planes[face2->planenum].normal, dir) > 0) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up with the grapple - if (facecenter[2] < areastart[2] + 64) continue; - //only use vertical faces or downward facing faces - if (DotProduct(aasworld.planes[face2->planenum].normal, down) < 0) continue; - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - // - z = dir[2]; - dir[2] = 0; - hordist = VectorLength(dir); - if (!hordist) continue; - //if too far - if (hordist > 2000) continue; - //check the minimal angle of the movement - mingrappleangle = 15; //15 degrees - if (z / hordist < tan(2 * M_PI * mingrappleangle / 360)) continue; - // - VectorCopy(facecenter, start); - VectorMA(facecenter, -500, aasworld.planes[face2->planenum].normal, end); - // - bsptrace = AAS_Trace(start, NULL, NULL, end, 0, CONTENTS_SOLID); - //the grapple won't stick to the sky and the grapple point should be near the AAS wall - if ((bsptrace.surface.flags & SURF_SKY) || (bsptrace.fraction * 500 > 32)) continue; - //trace a full bounding box from the area center on the ground to - //the center of the face - VectorSubtract(facecenter, areastart, dir); - VectorNormalize(dir); - VectorMA(areastart, 4, dir, start); - VectorCopy(bsptrace.endpos, end); - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - VectorSubtract(trace.endpos, facecenter, dir); - if (VectorLength(dir) > 24) continue; - // - VectorCopy(trace.endpos, start); - VectorCopy(trace.endpos, end); - end[2] -= AAS_FallDamageDistance(); - trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, -1); - if (trace.fraction >= 1) continue; - //area to end in - areanum = AAS_PointAreaNum(trace.endpos); - //if not in lava or slime - if (aasworld.areasettings[areanum].contents & (AREACONTENTS_SLIME|AREACONTENTS_LAVA)) - { - continue; - } //end if - //do not go the the source area - if (areanum == area1num) continue; - //don't create reachabilities if they already exist - if (AAS_ReachabilityExists(area1num, areanum)) continue; - //only end in areas we can stand - if (!AAS_AreaGrounded(areanum)) continue; - //never go through cluster portals!! - numareas = AAS_TraceAreas(areastart, bsptrace.endpos, areas, NULL, 20); - if (numareas >= 20) continue; - for (j = 0; j < numareas; j++) - { - if (aasworld.areasettings[areas[j]].contents & AREACONTENTS_CLUSTERPORTAL) break; - } //end for - if (j < numareas) continue; - //create a new reachability link - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = areanum; - lreach->facenum = face2num; - lreach->edgenum = 0; - VectorCopy(areastart, lreach->start); - //VectorCopy(facecenter, lreach->end); - VectorCopy(bsptrace.endpos, lreach->end); - lreach->traveltype = TRAVEL_GRAPPLEHOOK; - VectorSubtract(lreach->end, lreach->start, dir); - lreach->traveltime = aassettings.rs_startgrapple + VectorLength(dir) * 0.25; - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_grapple++; - } //end for - // - return qfalse; -} //end of the function AAS_Reachability_Grapple -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_SetWeaponJumpAreaFlags(void) -{ - int ent, i; - vec3_t mins = {-15, -15, -15}, maxs = {15, 15, 15}; - vec3_t origin; - int areanum, weaponjumpareas, spawnflags; - char classname[MAX_EPAIRKEY]; - - weaponjumpareas = 0; - for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) - { - if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; - if ( - !strcmp(classname, "item_armor_body") || - !strcmp(classname, "item_armor_combat") || - !strcmp(classname, "item_health_mega") || - !strcmp(classname, "weapon_grenadelauncher") || - !strcmp(classname, "weapon_rocketlauncher") || - !strcmp(classname, "weapon_lightning") || - !strcmp(classname, "weapon_plasmagun") || - !strcmp(classname, "weapon_railgun") || - !strcmp(classname, "weapon_bfg") || - !strcmp(classname, "item_quad") || - !strcmp(classname, "item_regen") || - !strcmp(classname, "item_invulnerability")) - { - if (AAS_VectorForBSPEpairKey(ent, "origin", origin)) - { - spawnflags = 0; - AAS_IntForBSPEpairKey(ent, "spawnflags", &spawnflags); - //if not a stationary item - if (!(spawnflags & 1)) - { - if (!AAS_DropToFloor(origin, mins, maxs)) - { - botimport.Print(PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", - classname, origin[0], origin[1], origin[2]); - } //end if - } //end if - //areanum = AAS_PointAreaNum(origin); - areanum = AAS_BestReachableArea(origin, mins, maxs, origin); - //the bot may rocket jump towards this area - aasworld.areasettings[areanum].areaflags |= AREA_WEAPONJUMP; - // - //if (!AAS_AreaGrounded(areanum)) - // botimport.Print(PRT_MESSAGE, "area not grounded\n"); - // - weaponjumpareas++; - } //end if - } //end if - } //end for - for (i = 1; i < aasworld.numareas; i++) - { - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - aasworld.areasettings[i].areaflags |= AREA_WEAPONJUMP; - weaponjumpareas++; - } //end if - } //end for - botimport.Print(PRT_MESSAGE, "%d weapon jump areas\n", weaponjumpareas); -} //end of the function AAS_SetWeaponJumpAreaFlags -//=========================================================================== -// create a possible weapon jump reachability from area1 to area2 -// -// check if there's a cool item in the second area -// check if area1 is lower than area2 -// check if the bot can rocketjump from area1 to area2 -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_Reachability_WeaponJump(int area1num, int area2num) -{ - int face2num, i, n, ret, visualize; - float speed, zvel, hordist; - aas_face_t *face2; - aas_area_t *area1, *area2; - aas_lreachability_t *lreach; - vec3_t areastart, facecenter, start, end, dir, cmdmove;// teststart; - vec3_t velocity; - aas_clientmove_t move; - aas_trace_t trace; - - visualize = qfalse; -// if (area1num == 4436 && area2num == 4318) -// { -// visualize = qtrue; -// } - if (!AAS_AreaGrounded(area1num) || AAS_AreaSwim(area1num)) return qfalse; - if (!AAS_AreaGrounded(area2num)) return qfalse; - //NOTE: only weapon jump towards areas with an interesting item in it?? - if (!(aasworld.areasettings[area2num].areaflags & AREA_WEAPONJUMP)) return qfalse; - // - area1 = &aasworld.areas[area1num]; - area2 = &aasworld.areas[area2num]; - //don't weapon jump towards way lower areas - if (area2->maxs[2] < area1->mins[2]) return qfalse; - // - VectorCopy(aasworld.areas[area1num].center, start); - //if not a swim area - if (!AAS_PointAreaNum(start)) Log_Write("area %d center %f %f %f in solid?\r\n", area1num, - start[0], start[1], start[2]); - VectorCopy(start, end); - end[2] -= 1000; - trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1); - if (trace.startsolid) return qfalse; - VectorCopy(trace.endpos, areastart); - // - //areastart is now the start point - // - for (i = 0; i < area2->numfaces; i++) - { - face2num = aasworld.faceindex[area2->firstface + i]; - face2 = &aasworld.faces[abs(face2num)]; - //if it is not a solid face - if (!(face2->faceflags & FACE_GROUND)) continue; - //get the center of the face - AAS_FaceCenter(face2num, facecenter); - //only go higher up with weapon jumps - if (facecenter[2] < areastart[2] + 64) continue; - //NOTE: set to 2 to allow bfg jump reachabilities - for (n = 0; n < 1/*2*/; n++) - { - //get the rocket jump z velocity - if (n) zvel = AAS_BFGJumpZVelocity(areastart); - else zvel = AAS_RocketJumpZVelocity(areastart); - //get the horizontal speed for the jump, if it isn't possible to calculate this - //speed (the jump is not possible) then there's no jump reachability created - ret = AAS_HorizontalVelocityForJump(zvel, areastart, facecenter, &speed); - if (ret && speed < 300) - { - //direction towards the face center - VectorSubtract(facecenter, areastart, dir); - dir[2] = 0; - hordist = VectorNormalize(dir); - //if (hordist < 1.6 * (facecenter[2] - areastart[2])) - { - //get command movement - VectorScale(dir, speed, cmdmove); - VectorSet(velocity, 0, 0, zvel); - /* - //get command movement - VectorScale(dir, speed, velocity); - velocity[2] = zvel; - VectorSet(cmdmove, 0, 0, 0); - */ - // - AAS_PredictClientMovement(&move, -1, areastart, PRESENCE_NORMAL, qtrue, - velocity, cmdmove, 30, 30, 0.1f, - SE_ENTERWATER|SE_ENTERSLIME| - SE_ENTERLAVA|SE_HITGROUNDDAMAGE| - SE_TOUCHJUMPPAD|SE_HITGROUND|SE_HITGROUNDAREA, area2num, visualize); - //if prediction time wasn't enough to fully predict the movement - //don't enter slime or lava and don't fall from too high - if (move.frames < 30 && - !(move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) - && (move.stopevent & (SE_HITGROUNDAREA|SE_TOUCHJUMPPAD))) - { - //create a rocket or bfg jump reachability from area1 to area2 - lreach = AAS_AllocReachability(); - if (!lreach) return qfalse; - lreach->areanum = area2num; - lreach->facenum = 0; - lreach->edgenum = 0; - VectorCopy(areastart, lreach->start); - VectorCopy(facecenter, lreach->end); - if (n) - { - lreach->traveltype = TRAVEL_BFGJUMP; - lreach->traveltime = aassettings.rs_bfgjump; - } //end if - else - { - lreach->traveltype = TRAVEL_ROCKETJUMP; - lreach->traveltime = aassettings.rs_rocketjump; - } //end else - lreach->next = areareachability[area1num]; - areareachability[area1num] = lreach; - // - reach_rocketjump++; - return qtrue; - } //end if - } //end if - } //end if - } //end for - } //end for - // - return qfalse; -} //end of the function AAS_Reachability_WeaponJump -//=========================================================================== -// calculates additional walk off ledge reachabilities for the given area -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_Reachability_WalkOffLedge(int areanum) -{ - int i, j, k, l, m, n, p, areas[10], numareas; - int face1num, face2num, face3num, edge1num, edge2num, edge3num; - int otherareanum, gap, reachareanum, side; - aas_area_t *area, *area2; - aas_face_t *face1, *face2, *face3; - aas_edge_t *edge; - aas_plane_t *plane; - vec_t *v1, *v2; - vec3_t sharededgevec, mid, dir, testend; - aas_lreachability_t *lreach; - aas_trace_t trace; - - if (!AAS_AreaGrounded(areanum) || AAS_AreaSwim(areanum)) return; - // - area = &aasworld.areas[areanum]; - // - for (i = 0; i < area->numfaces; i++) - { - face1num = aasworld.faceindex[area->firstface + i]; - face1 = &aasworld.faces[abs(face1num)]; - //face 1 must be a ground face - if (!(face1->faceflags & FACE_GROUND)) continue; - //go through all the edges of this ground face - for (k = 0; k < face1->numedges; k++) - { - edge1num = aasworld.edgeindex[face1->firstedge + k]; - //find another not ground face using this same edge - for (j = 0; j < area->numfaces; j++) - { - face2num = aasworld.faceindex[area->firstface + j]; - face2 = &aasworld.faces[abs(face2num)]; - //face 2 may not be a ground face - if (face2->faceflags & FACE_GROUND) continue; - //compare all the edges - for (l = 0; l < face2->numedges; l++) - { - edge2num = aasworld.edgeindex[face2->firstedge + l]; - if (abs(edge1num) == abs(edge2num)) - { - //get the area at the other side of the face - if (face2->frontarea == areanum) otherareanum = face2->backarea; - else otherareanum = face2->frontarea; - // - area2 = &aasworld.areas[otherareanum]; - //if the other area is grounded! - if (aasworld.areasettings[otherareanum].areaflags & AREA_GROUNDED) - { - //check for a possible gap - gap = qfalse; - for (n = 0; n < area2->numfaces; n++) - { - face3num = aasworld.faceindex[area2->firstface + n]; - //may not be the shared face of the two areas - if (abs(face3num) == abs(face2num)) continue; - // - face3 = &aasworld.faces[abs(face3num)]; - //find an edge shared by all three faces - for (m = 0; m < face3->numedges; m++) - { - edge3num = aasworld.edgeindex[face3->firstedge + m]; - //but the edge should be shared by all three faces - if (abs(edge3num) == abs(edge1num)) - { - if (!(face3->faceflags & FACE_SOLID)) - { - gap = qtrue; - break; - } //end if - // - if (face3->faceflags & FACE_GROUND) - { - gap = qfalse; - break; - } //end if - //FIXME: there are more situations to be handled - gap = qtrue; - break; - } //end if - } //end for - if (m < face3->numedges) break; - } //end for - if (!gap) break; - } //end if - //check for a walk off ledge reachability - edge = &aasworld.edges[abs(edge1num)]; - side = edge1num < 0; - // - v1 = aasworld.vertexes[edge->v[side]]; - v2 = aasworld.vertexes[edge->v[!side]]; - // - plane = &aasworld.planes[face1->planenum]; - //get the points really into the areas - VectorSubtract(v2, v1, sharededgevec); - CrossProduct(plane->normal, sharededgevec, dir); - VectorNormalize(dir); - // - VectorAdd(v1, v2, mid); - VectorScale(mid, 0.5, mid); - VectorMA(mid, 8, dir, mid); - // - VectorCopy(mid, testend); - testend[2] -= 1000; - trace = AAS_TraceClientBBox(mid, testend, PRESENCE_CROUCH, -1); - // - if (trace.startsolid) - { - //Log_Write("area %d: trace.startsolid\r\n", areanum); - break; - } //end if - reachareanum = AAS_PointAreaNum(trace.endpos); - if (reachareanum == areanum) - { - //Log_Write("area %d: same area\r\n", areanum); - break; - } //end if - if (AAS_ReachabilityExists(areanum, reachareanum)) - { - //Log_Write("area %d: reachability already exists\r\n", areanum); - break; - } //end if - if (!AAS_AreaGrounded(reachareanum) && !AAS_AreaSwim(reachareanum)) - { - //Log_Write("area %d, reach area %d: not grounded and not swim\r\n", areanum, reachareanum); - break; - } //end if - // - if (aasworld.areasettings[reachareanum].contents & (AREACONTENTS_SLIME - | AREACONTENTS_LAVA)) - { - //Log_Write("area %d, reach area %d: lava or slime\r\n", areanum, reachareanum); - break; - } //end if - //if not going through a cluster portal - numareas = AAS_TraceAreas(mid, testend, areas, NULL, sizeof(areas) / sizeof(int)); - for (p = 0; p < numareas; p++) - if (AAS_AreaClusterPortal(areas[p])) - break; - if (p < numareas) - break; - // if a maximum fall height is set and the bot would fall down further - if (aassettings.rs_maxfallheight && fabs(mid[2] - trace.endpos[2]) > aassettings.rs_maxfallheight) - break; - // - lreach = AAS_AllocReachability(); - if (!lreach) break; - lreach->areanum = reachareanum; - lreach->facenum = 0; - lreach->edgenum = edge1num; - VectorCopy(mid, lreach->start); - VectorCopy(trace.endpos, lreach->end); - lreach->traveltype = TRAVEL_WALKOFFLEDGE; - lreach->traveltime = aassettings.rs_startwalkoffledge + fabs(mid[2] - trace.endpos[2]) * 50 / aassettings.phys_gravity; - if (!AAS_AreaSwim(reachareanum) && !AAS_AreaJumpPad(reachareanum)) - { - if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta5) - { - lreach->traveltime += aassettings.rs_falldamage5; - } //end if - else if (AAS_FallDelta(mid[2] - trace.endpos[2]) > aassettings.phys_falldelta10) - { - lreach->traveltime += aassettings.rs_falldamage10; - } //end if - } //end if - lreach->next = areareachability[areanum]; - areareachability[areanum] = lreach; - //we've got another walk off ledge reachability - reach_walkoffledge++; - } //end if - } //end for - } //end for - } //end for - } //end for -} //end of the function AAS_Reachability_WalkOffLedge -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_StoreReachability(void) -{ - int i; - aas_areasettings_t *areasettings; - aas_lreachability_t *lreach; - aas_reachability_t *reach; - - if (aasworld.reachability) FreeMemory(aasworld.reachability); - aasworld.reachability = (aas_reachability_t *) GetClearedMemory((numlreachabilities + 10) * sizeof(aas_reachability_t)); - aasworld.reachabilitysize = 1; - for (i = 0; i < aasworld.numareas; i++) - { - areasettings = &aasworld.areasettings[i]; - areasettings->firstreachablearea = aasworld.reachabilitysize; - areasettings->numreachableareas = 0; - for (lreach = areareachability[i]; lreach; lreach = lreach->next) - { - reach = &aasworld.reachability[areasettings->firstreachablearea + - areasettings->numreachableareas]; - reach->areanum = lreach->areanum; - reach->facenum = lreach->facenum; - reach->edgenum = lreach->edgenum; - VectorCopy(lreach->start, reach->start); - VectorCopy(lreach->end, reach->end); - reach->traveltype = lreach->traveltype; - reach->traveltime = lreach->traveltime; - // - areasettings->numreachableareas++; - } //end for - aasworld.reachabilitysize += areasettings->numreachableareas; - } //end for -} //end of the function AAS_StoreReachability -//=========================================================================== -// -// TRAVEL_WALK 100% equal floor height + steps -// TRAVEL_CROUCH 100% -// TRAVEL_BARRIERJUMP 100% -// TRAVEL_JUMP 80% -// TRAVEL_LADDER 100% + fall down from ladder + jump up to ladder -// TRAVEL_WALKOFFLEDGE 90% walk off very steep walls? -// TRAVEL_SWIM 100% -// TRAVEL_WATERJUMP 100% -// TRAVEL_TELEPORT 100% -// TRAVEL_ELEVATOR 100% -// TRAVEL_GRAPPLEHOOK 100% -// TRAVEL_DOUBLEJUMP 0% -// TRAVEL_RAMPJUMP 0% -// TRAVEL_STRAFEJUMP 0% -// TRAVEL_ROCKETJUMP 100% (currently limited towards areas with items) -// TRAVEL_BFGJUMP 0% (currently disabled) -// TRAVEL_JUMPPAD 100% -// TRAVEL_FUNCBOB 100% -// -// Parameter: - -// Returns: true if NOT finished -// Changes Globals: - -//=========================================================================== -int AAS_ContinueInitReachability(float time) -{ - int i, j, todo, start_time; - static float framereachability, reachability_delay; - static int lastpercentage; - - if (!aasworld.loaded) return qfalse; - //if reachability is calculated for all areas - if (aasworld.numreachabilityareas >= aasworld.numareas + 2) return qfalse; - //if starting with area 1 (area 0 is a dummy) - if (aasworld.numreachabilityareas == 1) - { - botimport.Print(PRT_MESSAGE, "calculating reachability...\n"); - lastpercentage = 0; - framereachability = 2000; - reachability_delay = 1000; - } //end if - //number of areas to calculate reachability for this cycle - todo = aasworld.numreachabilityareas + (int) framereachability; - start_time = Sys_MilliSeconds(); - //loop over the areas - for (i = aasworld.numreachabilityareas; i < aasworld.numareas && i < todo; i++) - { - aasworld.numreachabilityareas++; - //only create jumppad reachabilities from jumppad areas - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - continue; - } //end if - //loop over the areas - for (j = 1; j < aasworld.numareas; j++) - { - if (i == j) continue; - //never create reachabilities from teleporter or jumppad areas to regular areas - if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) - { - if (!(aasworld.areasettings[j].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD))) - { - continue; - } //end if - } //end if - //if there already is a reachability link from area i to j - if (AAS_ReachabilityExists(i, j)) continue; - //check for a swim reachability - if (AAS_Reachability_Swim(i, j)) continue; - //check for a simple walk on equal floor height reachability - if (AAS_Reachability_EqualFloorHeight(i, j)) continue; - //check for step, barrier, waterjump and walk off ledge reachabilities - if (AAS_Reachability_Step_Barrier_WaterJump_WalkOffLedge(i, j)) continue; - //check for ladder reachabilities - if (AAS_Reachability_Ladder(i, j)) continue; - //check for a jump reachability - if (AAS_Reachability_Jump(i, j)) continue; - } //end for - //never create these reachabilities from teleporter or jumppad areas - if (aasworld.areasettings[i].contents & (AREACONTENTS_TELEPORTER|AREACONTENTS_JUMPPAD)) - { - continue; - } //end if - //loop over the areas - for (j = 1; j < aasworld.numareas; j++) - { - if (i == j) continue; - // - if (AAS_ReachabilityExists(i, j)) continue; - //check for a grapple hook reachability - if (calcgrapplereach) AAS_Reachability_Grapple(i, j); - //check for a weapon jump reachability - AAS_Reachability_WeaponJump(i, j); - } //end for - //if the calculation took more time than the max reachability delay - if (Sys_MilliSeconds() - start_time > (int) reachability_delay) break; - // - if (aasworld.numreachabilityareas * 1000 / aasworld.numareas > lastpercentage) break; - } //end for - // - if (aasworld.numreachabilityareas == aasworld.numareas) - { - botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) 100.0); - botimport.Print(PRT_MESSAGE, "\nplease wait while storing reachability...\n"); - aasworld.numreachabilityareas++; - } //end if - //if this is the last step in the reachability calculations - else if (aasworld.numreachabilityareas == aasworld.numareas + 1) - { - //create additional walk off ledge reachabilities for every area - for (i = 1; i < aasworld.numareas; i++) - { - //only create jumppad reachabilities from jumppad areas - if (aasworld.areasettings[i].contents & AREACONTENTS_JUMPPAD) - { - continue; - } //end if - AAS_Reachability_WalkOffLedge(i); - } //end for - //create jump pad reachabilities - AAS_Reachability_JumpPad(); - //create teleporter reachabilities - AAS_Reachability_Teleport(); - //create elevator (func_plat) reachabilities - AAS_Reachability_Elevator(); - //create func_bobbing reachabilities - AAS_Reachability_FuncBobbing(); - // -#ifdef DEBUG - botimport.Print(PRT_MESSAGE, "%6d reach swim\n", reach_swim); - botimport.Print(PRT_MESSAGE, "%6d reach equal floor\n", reach_equalfloor); - botimport.Print(PRT_MESSAGE, "%6d reach step\n", reach_step); - botimport.Print(PRT_MESSAGE, "%6d reach barrier\n", reach_barrier); - botimport.Print(PRT_MESSAGE, "%6d reach waterjump\n", reach_waterjump); - botimport.Print(PRT_MESSAGE, "%6d reach walkoffledge\n", reach_walkoffledge); - botimport.Print(PRT_MESSAGE, "%6d reach jump\n", reach_jump); - botimport.Print(PRT_MESSAGE, "%6d reach ladder\n", reach_ladder); - botimport.Print(PRT_MESSAGE, "%6d reach walk\n", reach_walk); - botimport.Print(PRT_MESSAGE, "%6d reach teleport\n", reach_teleport); - botimport.Print(PRT_MESSAGE, "%6d reach funcbob\n", reach_funcbob); - botimport.Print(PRT_MESSAGE, "%6d reach elevator\n", reach_elevator); - botimport.Print(PRT_MESSAGE, "%6d reach grapple\n", reach_grapple); - botimport.Print(PRT_MESSAGE, "%6d reach rocketjump\n", reach_rocketjump); - botimport.Print(PRT_MESSAGE, "%6d reach jumppad\n", reach_jumppad); -#endif - //*/ - //store all the reachabilities - AAS_StoreReachability(); - //free the reachability link heap - AAS_ShutDownReachabilityHeap(); - // - FreeMemory(areareachability); - // - aasworld.numreachabilityareas++; - // - botimport.Print(PRT_MESSAGE, "calculating clusters...\n"); - } //end if - else - { - lastpercentage = aasworld.numreachabilityareas * 1000 / aasworld.numareas; - botimport.Print(PRT_MESSAGE, "\r%6.1f%%", (float) lastpercentage / 10); - } //end else - //not yet finished - return qtrue; -} //end of the function AAS_ContinueInitReachability -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_InitReachability(void) -{ - if (!aasworld.loaded) return; - - if (aasworld.reachabilitysize) - { -#ifndef BSPC - if (!((int)LibVarGetValue("forcereachability"))) - { - aasworld.numreachabilityareas = aasworld.numareas + 2; - return; - } //end if -#else - aasworld.numreachabilityareas = aasworld.numareas + 2; - return; -#endif //BSPC - } //end if -#ifndef BSPC - calcgrapplereach = LibVarGetValue("grapplereach"); -#endif - aasworld.savefile = qtrue; - //start with area 1 because area zero is a dummy - aasworld.numreachabilityareas = 1; - ////aasworld.numreachabilityareas = aasworld.numareas + 1; //only calculate entity reachabilities - //setup the heap with reachability links - AAS_SetupReachabilityHeap(); - //allocate area reachability link array - areareachability = (aas_lreachability_t **) GetClearedMemory( - aasworld.numareas * sizeof(aas_lreachability_t *)); - // - AAS_SetWeaponJumpAreaFlags(); -} //end of the function AAS_InitReachable |